Finding Unmatched Records in Dataset Tables Using Linq
http://www.eggheadcafe.com/tutorials/aspnet/9b443d4a-0ec3-4599-be41-d4454c1fbd9b/finding-unmatched-records.aspx

1. LINQ(Language Integrated Query )
http://msdn.microsoft.com/ko-kr/library/bb397926.aspx
쿼리를 이용하여 개체와 데이터 간 격차를 줄여주는 기술.
객체지향 기술을 사용하여 네이티브에 정의되지 않은 정보 접근이나 통합의 복잡함을 경감시키는 방식으로  모든 Data소스에 대해 쿼리가 가능하게 한 framework  
주요장점들
   -  여러 조건을 필터링할 때 더욱 명료하며 읽기 쉽다.
   -  최소한의 응용 프로그램 코드를 사용하여 강력한 필터링, 정렬 및 그룹화 기능을 제공.
   -  거의 수정하지 않거나 약간만 수정하여 다른 데이터 소스에 이식할 수 있다.

1.1 다양한 종류의 데이터 소스와 형식에서 작업하기 위한 일관된 모델을 제공

1.1.1 쿼리 가능한 형식 
   - IEnumerable 또는 IEnumerable<(Of <(T>)>)
   - IQueryable<(Of <(T>)>) 같은 파생 인터페이스를 지원하는 형식
   - SQL Server 데이터베이스, XML 문서, ADO.NET 데이터 집합 

1.2. 코딩시 기본 쿼리 작업 특징들

// Data source.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
1.2.0 쿼리생성(Query creation)
// var 키워드는 from 절에 지정된 데이터 소스를 검사하여 쿼리 변수의 형식을 추론하도록  컴파일러에 지시
// numQuery변수는는 이 쿼리식만 가지고 실행은 되지 않는다.
var numQuery =  
        from num in numbers where (num % 2) == 0
        select num;

1.2.1. 지연실행
foreach문 사용 시 실재로 실행을함
        foreach (int num in numQuery)
            Console.Write("{0,1} ", num);
1.2.2. 즉시실행강제
-  Count, Max, Average 및 First와 같은 집계함수를 수행 할 때는 내부적으로 내장 foreach문이 실행됨
       int numCount = numQuery .Count();
1.2.3.  실행결과 캐싱
-  ToList<(Of <(TSource>)>) 또는 ToArray<(Of <(TSource>)>) 메서드를 호출 결과를 캐싱
         List<int> numQuery2 = (from num in numbers where (num % 2) == 0 select num).ToList();
        // or like this:
        var numQuery3 = (from num in numbers where (num % 2) == 0 select num).ToArray();
1.2.4.
정렬
      var queryLondonCustomers3 = 
             from cust in customers where cust.City == "London"
            
orderby cust.Name ascending
             select cust;
1.2.5. 그룹화
-
group 절은 그룹의 키 값과 일치하는 하나 이상의 항목을 포함하는 IGrouping<(Of <(TKey, TElement>)>) 개체 시퀀스를 반환
      // Query variable is an IEnumerable<IGrouping<char, Student>>
      var studentQuery1 =
      from student in students
      group student by student.Last[0]; //char형 키를 저장하게된다.

1.2.5.1. 각 그룹에서 추가 쿼리 작업을 수행하려면  into 컨텍스트키워드를 이용하여 임시식별자를 만들어서 수행
      // custQuery is an IEnumerable<IGrouping<string, Customer>>
      var custQuery = from cust in customers
      group cust by cust.City into custGroup
      where
custGroup.Count() > 2
      orderby custGroup.Key
      select custGroup;

1.2.5.2. 그룹쿼리 결과얻기
      // Iterate group items with a nested foreach. This IGrouping encapsulates a sequence of Student objects, and a Key of type char.
      // For convenience, var can also be used in the foreach statement.
       foreach (IGrouping<char, Student> studentGroup in studentQuery2)
      {
            Console.WriteLine(studentGroup.Key);
            // Explicit type for student could also be used here.
            foreach (var student in studentGroup)
           {
                Console.WriteLine("   {0}, {1}", student.Last, student.First);
           }
       }
       
1.2.5.3. 그루핑 시 키 지정
        그룹 키는 문자열, 기본 제공 숫자 형식 또는 사용자 정의 명명된 형식이나 익명 형식과 같은 임의의 형식가능

1.2.5.3.1. 문자열값으로 그룹화예
 Query variable(studentQuery3 ) is an IEnumerable<IGrouping<string, Student>> 이 됨
 var studentQuery3 = from student in students group student by student.Last;

1.2.5.3.2. 부울값으로 그룹화 예
 group by 다음에 조건을 지정하여 조건에 해당하는 두 그룹으로 나누는 경우
 데이타가 아래와 같이 정의된경우,
         List<Student> students = new List<Student>
        {
           new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 81, 60}},
           new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
           new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {99, 89, 91, 95}},
           new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
           new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}}
        };
 다음과 같이 조건으로 그루핑하면 키값이 boolean형으로 저장됨
         var booleanGroupQuery =
            from student in students
            group student by student.Scores.Average() >= 80; //pass or fail!

        // Execute the query and access items in each group
        foreach (var studentGroup in booleanGroupQuery)
        {
            Console.WriteLine(studentGroup.Key == true ? "High averages" : "Low averages");
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
            }
        }
1.2.5.3.3. 숫자범위로 그룹화 예
 group by 다음에 범위형태로 조건을 줄 수도 있다. 10단위로 키값이 그루핑되나봅니다.
        var studentQuery =
            from student in students
            let avg = (int)student.Scores.Average()
            group student by (avg == 0 ? 0 : avg / 10) into g
            orderby g.Key
            select g;           

        // Execute the query.
        foreach (var studentGroup in studentQuery)
        {
            int temp = studentGroup.Key * 10;
            Console.WriteLine("Students with an average between {0} and {1}", temp, temp + 10);
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
            }
        }
1.2.5.3.3. 복합키로 그룹화 예
group person by new {name = person.surname, city = person.city};

1.2.6. 조인

1.2.6.1. 내부조인
  var innerJoinQuery =
  from category in categories
            join prod in products on category.ID equals prod.CategoryID
  select new { ProductName = prod.Name, Category = category.Name }; //produces flat sequence

1.2.6.2. 그룹조인
  - into 식이 있는 join 절을 그룹 조인을 말한다. T-Sql에 이런게 없는걸로 아는데... 재미난 조인인듯
  - 그룹 조인은 왼쪽 소스 시퀀스의 요소를 오른쪽 소스 시퀀스에 있는 하나 이상의 일치하는 요소와 연결하는 계층적 결과를 생성
  - 왼쪽 소스의 요소와 일치하는 오른쪽 소스 시퀀스의 요소가 없을 경우 join 절은 해당 항목에 대해 빈 배열을 생성
  - 그룹 조인은 결과 시퀀스가 그룹으로 구성된다는 점을 제외하고 기본적으로 내부 동등 조인과 같다?
    var innerGroupJoinQuery = 
    from category in categories  
               join prod in products on category.ID equals prod.CategoryID
into prodGroup
    select new { CategoryName = category.Name, Products = prodGroup };
  - 그룹 조인의 결과를 다른 하위 쿼리의 생성기로 사용 (T-Sql에서 중첩쿼리에 해당하겠네요)
    var innerGroupJoinQuery2 =
    from category in categories
               join prod in products on category.ID equals prod.CategoryID into prodGroup
    from prod2 in prodGroup
    where prod2.UnitPrice > 2.50M
    select prod2;   

1.2.6.3.
왼쪽우선 외부조인 (Tsql의 Left Outer Join)
  - LINQ에서 왼쪽 우선 외부 조인을 수행하려면 DefaultIfEmpty 메서드를 그룹 조인과 함께 사용하여
    왼쪽 요소에 일치 항목이 없을 경우 생성할 기본 오른쪽 요소를 지정
    문법이 매끄럽지가 못하다는 느낌이...(그냥 Left Join으로 표기하지 않구.. 엄청 어렵게 표현T.T)
          var leftOuterJoinQuery =
          from category in categories
                   join prod in products on category.ID equals prod.CategoryID
into prodGroup
          from item in prodGroup.DefaultIfEmpty(new Product{Name = String.Empty, CategoryID = 0})
          select new { CatName = category.Name, ProdName = item.Name };

1.2.6.4. 개체 컬렉션 및 관계형 테이블의 조인
         LINQ 쿼리 식에서는 조인 작업이 개체 컬렉션에서 수행되며 두 개의 관계형 테이블과 동일한 방식으로 "조인"할 수 없다.
         LINQ에서 명시적 join 절은 두 개의 소스 콜렉션이 어떤 관계로도 연결되지 않은 경우에만 필요
         LINQ to SQL을 사용하는 경우 외래 키 테이블은 개체 모델에 기본 테이블의 속성으로 표현되므로 조인이 이미 된 상태임
        ( 예를 들어 Northwind 데이터베이스의 Customer 테이블은 Orders 테이블과 외래 키 관계가 있습니다.
          테이블을 개체 모델에 매핑하면 Customer 클래스에 해당 Customer와 연결된 Orders 컬렉션을 포함하는 Orders 속성이 자동생성됨)

 1.2.6.5. 복합키 조인 
         익명 형식의 복합 키를 만들거나, 비교할 값이 포함된 명명된 형식으로 복합 키를 만듬.
        (참고: db라는 collection의 속성으로 Orders와 Products가 이미 포함되었다고 가정함)
         var query = 
         from o in db.Orders
         from p in db.Products
                          join d in db.OrderDetails on new {o.OrderID, p.ProductID} equals new {d.OrderID,        d.ProductID}
         into details
         from d in details
         select new {o.OrderID, p.ProductID, d.UnitPrice};    

1.3. LINQ를 통한 데이터 변환
 LINQ(통합 언어 쿼리)는 데이터를 검색할 뿐 아니라 데이터를 변환하는 강력한 도구.
 LINQ 쿼리를 사용하면 소스 시퀀스를 입력으로 사용하고 다양한 방식으로 수정하여 새 출력 시퀀스를 만들 수 있다.
 LINQ 쿼리의 가장 강력한 기능은 select절을 이용한 새 형식을 만드는 기능

1.3.1. 여러 입력을 하나의 출력 시퀀스로 결합 
두 개의 메모리 내 데이터 구조를 결합하는 방법을 보여 주지만, XML이나 SQL 또는 DataSet 소스의 데이터를 결합하는 경우에도 동일한 원칙을 적용할 수 있다.        
        // Create the first data source.
        List<Student> students = new List<Student>()
        {
            new Student {First="Svetlana", Last="Omelchenko",  ID=111, Street="123 Main Street", City="Seattle", Scores= new List<int> {97, 92, 81, 60}},
            new Student {First="Claire", Last="O’Donnell",  ID=112, Street="124 Main Street", City="Redmond", Scores= new List<int> {75, 84, 91, 39}},
            new Student {First="Sven", Last="Mortensen", ID=113, Street="125 Main Street", City="Lake City", Scores= new List<int> {88, 94, 65, 91}},
        };

        // Create the second data source.
        List<Teacher> teachers = new List<Teacher>()
        {               
            new Teacher {First="Ann", Last="Beebe", ID=945, City = "Seattle"},
            new Teacher {First="Alex", Last="Robinson", ID=956, City = "Redmond"},
            new Teacher {First="Michiyo", Last="Sato", ID=972, City = "Tacoma"}
        };

        // Create the query.
        var peopleInSeattle =
        (
           from student in students
           where student.City == "Seattle"
           select student.Last
        )
        .Concat  // 쿼리의 union all 에 해당
       (
          from teacher in teachers
          where teacher.City == "Seattle"
          select teacher.Last
       );

        Console.WriteLine("The following students and teachers live in Seattle:");
       
        // Execute the query.
        foreach (var person in peopleInSeattle)
        {
            Console.WriteLine(person);
        }

1.3.2. 각 소스 요소의 하위 집합 선택 
 - 단순한 Select
    var query = from cust in Customers
            select cust.City;
 - 새로운 인스턴트스로 생성하며 select
   var query = from cust in Customer
            select new {Name = cust.Name, City = cust.City}; 

1.3.3. 메모리 내부 개체를 XML로 변환 
// Create the data source by using a collection initializer.
        List<Student> students = new List<Student>()
        {
            new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},
            new Student {First="Claire", Last="O’Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},
            new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},
        };

        // Create the query. 이렇게 XElement를 이용하여~~~
        var studentsToXML =
        new XElement("Root",
            from student in students
            let x = String.Format("{0},{1},{2},{3}", student.Scores[0], student.Scores[1], student.Scores[2], student.Scores[3])
            select new XElement("student",
                       new XElement("First", student.First),
                       new XElement("Last", student.Last),
                       new XElement("Scores", x)
                    ) // end "student"
                ); // end "Root"

        // Execute the query.
        Console.WriteLine(studentsToXML);

1.3.4.  소스 요소에서 작업 수행
        // Data source.
        double[] radii = { 1, 2, 3 };

        // Query.
        IEnumerable<string> query =
            from rad in radii
            select String.Format("Area = {0}", (rad * rad) * 3.14);

        // Query execution.
        foreach (string s in query)
            Console.WriteLine(s);

1.4. 쿼리 구문과 메서드 구문 비교
NET CLR(공용 언어 런타임) 자체에는 쿼리 구문의 개념이 없고 컴파일 타임에 쿼리 식은 CLR이 인식가능한 메서드 호출로 변환됨
이러한 메서드를 표준 쿼리 연산자 라고 하며 Where, Select, GroupBy, Join, Max, Average,... 등이 있다.
쿼리 구문 대신 메서드 구문을 사용하여 이를 직접 호출할 수 있다.
          int[] numbers = { 5, 10, 8, 3, 6, 12};
         //Query syntax:
        IEnumerable<int> numQuery1 =
            from num in numbers
            where num % 2 == 0
            orderby num
            select num;

        //Method syntax:
        IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
둘의 결과는 동일하다.
Where(num => num % 2 == 0) 이 인라인 식을 람다식 이라한다.
람다식을 사용하지 않을 경우 익명 메서드나 제네릭 대리자 또는 식 트리와 같은 형식으로 코드를 작성해야 한다.
C#에서 =>는 "goes to"를 나타내는 람다 연산자
 

1.5. 람다식
http://msdn.microsoft.com/ko-kr/library/bb397687.aspx 계속
http://msdn.microsoft.com/ko-kr/library/bb397951.aspx 식트리
http://msdn.microsoft.com/ko-kr/library/bb882636.aspx
식과 문을 포함하고 대리자나 식 트리 형식을 만드는 데 사용할 수 있는 익명 함수
모든 람다 식에는 람다 연산자 =>("이동"이라고 읽음)사용
왼쪽에는 입력 매개 변수(있는 경우)를 지정하고 오른쪽에는 식 또는 문 블록이 위치
=> 연산자는 할당 연산자(=)와 우선 순위가 같으며 오른쪽 결합성이 있다.
예) x => x * x라는 람다 식은 "x는 x 곱하기 x로 이동"으로 읽으며, 이 식은 다음과 같이 대리자 형식에 할당할 수 있다.
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25

메서드 기반 LINQ 쿼리에서 Where 및 Where 같은 표준 쿼리 연산자 메서드의 인수로 사용.
LINQ to Objects 및 LINQ to XML에서처럼 메서드 기반의 구문을 사용하여 Enumerable 클래스에서 Where 메서드를 호출하는 경우
매개 변수는 System..::.Func<(Of <(T, TResult>)>) 대리자 형식
람다식은 대리자를 만드는 가장 간단한 방법이다.
LINQ to SQL에서 System.Linq..::.Queryable 클래스 에서 호출하는 경우 매개 변수 형식은 System.Linq.Expressions..::.Expression<Func>이고, 여기서 Func는 입력 매개 변수를 5개까지 가질 수 있는 임의의 Func 대리자이다.

1.5.1. 식 람다(expression lamda)
- 오른쪽에 식이 있는 람다 식,  식 트리를 만드는 데 광범위하게 사용,식 람다는 식의 결과를 반환
 (input parameters) => expression
- 괄호는 람다 식에 입력 매개 변수가 하나뿐인 경우에만 생략
- 둘 이상의 입력 매개 변수는 다음과 같이 괄호로 묶고 쉼표로 구분
 (x, y) => x == y
- 컴파일러에서 입력 형식을 유추할 수 없는 경우 다음과 같이 형식을 명시적으로 지정
 (int x, string s) => s.Length > x
- 입력 매개 변수가 0개이면 다음과 같이 빈 괄호를 지정
 () => SomeMethod()
1.5.2.  식트리
System.Linq.Expressions 네임스페이스 필요
IQueryable<(Of <(T>)>)을 구현하는 데이터의 소스를 대상으로 하는 구조화된 쿼리를 나타내기 위해 식 트리를 사용
LINQ에서 Expression<(Of <(TDelegate>)>) 형식 변수에 할당되는 람다 식을 나타내는 데에도 사용
   Expression<Func<int, bool>> exprTree = num => num < 5;
   와같이 Delegate표현대신 Expression클래스 형식을 사용하여 트리형태로 식을저장
ParameterExpression,ConstantExpression,BinaryExpression등과같이 식에표현된 각 부분에 해당하는 클래스들존재

// Manually build the expression tree for the lambda expression num => num < 5.
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });
와 동일한 람다식표현
// Let the compiler generate the expression tree for the lambda expression num => num < 5.
Expression<Func<int, bool>> lambda2 = num => num < 5;
이정도 개념만 있어도 충분할듯, 더 자세한 부분은 MSDN을 찾아보시고 http://msdn.microsoft.com/ko-kr/library/bb882637.aspx


1.5.3. 문 람다 (statement lamda)
- 문 람다는 다음과 같이 중괄호 안에 문을 지정한다는 점을 제외하면 식 람다와 비슷
 (input parameters) => {statement;}
- 문 람다의 본문에 지정할 수 있는 문의 개수에는 제한이 없지만 일반적으로 2-3개 정도만 지정
  (문 람다는 식 트리를 만드는 데 사용될 수 없다)
 delegate void TestDelegate(string s);
 …
 TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
 myDel("Hello");

1.5.4. 표준 쿼리 연산자와 람다 식
- 대부분의 표준 쿼리 연산자에는 형식이 제네릭 대리자의 Func<(Of <(T, TResult>)>) 패밀리 중 하나인 입력 매개 변수를 사용
 public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
 이 경우 대리자를 Func<int,bool> myFunc로 인스턴스화할 수 있다.
 int는 입력 매개 변수이고, bool은 반환 값(반환 값은 항상 마지막 형식 매개 변수로 지정)

예) 5인지 여부판단하여 bool로 리턴
    Func<int, bool> myFunc = x => x == 5;
    bool result = myFunc(4); // returns false of course
- System.Linq.Queryable에 정의되어 있는 표준 쿼리 연산자의 경우와 같이 인수 형식이 Expression<Func>인 경우에도 람다 식을 사용.
  Expression<Func> 인수를 지정하면 식 트리에 람다 식이 컴파일됨

예) 2로 나누었을 때 나머지가 1인 정수(n)의 수를 계산
      int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
      int oddNumbers = numbers.Count(n => n % 2 == 1);
    시작부터 검사하여 6보다 작은 값들 추출
      var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
    2개의 파라메타를 입력받아 동적으로 임계치 변경
      var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);

1.5.5. 람다 식에서의 형식 유추
입력 매개 변수의 형식은 대부분의 표준 쿼리 연산자에서 첫 번째 입력 형식은 소스 시퀀스 요소의 형식으로 컴파일러가 유추함
IEnumerable<Customer>을 쿼리할 경우 입력 변수가 Customer 개체로 유추
customers.Where(c => c.City == "London");
- 람다 식적용 규칙
  람다 식과 대리자 형식에 포함된 매개 변수 수가 같아야 한다. 
   람다 식의 각 입력 매개 변수는 해당되는 대리자 매개 변수로 암시적으로 변환될 수 있어야 한다.
  람다 식의 반환 값(있는 경우)은 대리자의 반환 형식으로 암시적으로 변환될 수 있어야 한다.
  람다 식의 "형식"을 비공식적으로 언급해야 할 경우 대리자 형식 또는 람다 식이 변환되는 Expression 형식을 의미

1.5.6. 람다 식의 변수 범위
람다 식은 람다 식이 정의된 바깥쪽 메서드나 형식의 범위에 포함되어 있는 외부 변수를 참조할 수 있다.
이러한 방식으로 캡처되는 변수는 변수가 범위를 벗어나 가비지 수집되는 경우에도 람다 식에 사용할 수 있도록 저장된다.
외부 변수는 명확하게 할당해야만 람다 식에 사용할 수 있다
- 람다 식의 변수 범위규칙
  캡처된 변수는 해당 변수를 참조하는 대리자가 범위에서 벗어날 때까지 가비지 수집되지 않는다.
  람다 식에 사용된 변수는 외부 메서드에 표시되지 않는다.
  람다 식은 바깥쪽 메서드에서 ref 또는 out 매개 변수를 직접 캡처할 수 없습니다.
  람다 식의 return 문에 의해서는 바깥쪽 메서드가 반환되지는 않는다.?
  람다 식에는 포함된 익명 함수의 본문 또는 본문 외부를 대상으로 하는 goto 문, break 문 또는 continue 문이 포함될 수 없다

예)
    delegate bool D();
    delegate bool D2(int i);

    class Test
    {
        D del;
        D2 del2;
        public void TestMethod(int input)
        {
            int j = 0;
            // Initialize the delegates with lambda expressions.
            // Note access to 2 outer variables.
            // del will be invoked within this method.
            del = () => { j = 10;  return j > input; };

            // del2 will be invoked after TestMethod goes out of scope.
            del2 = (x) => {return x == j; };
           
            // Demonstrate value of j:
            // Output: j = 0
            // The delegate has not been invoked yet.
            Console.WriteLine("j = {0}", j);

            // Invoke the delegate.
            bool boolResult = del();

            // Output: j = 10 b = True
            Console.WriteLine("j = {0}. b = {1}", j, boolResult);
        }

        static void Main()
        {
            Test test = new Test();
            test.TestMethod(5);

            // Prove that del2 still has a copy of
            // local variable j from TestMethod.
            bool result = test.del2(10);

            // Output: True
            Console.WriteLine(result);
           
            Console.ReadKey();
        }
    }

2. LINQ to Objects
중간 LINQ 공급자나 API는 사용하지 않고 LINQ to SQL,LINQ to XML처럼 IEnumerable,IEnumerable<(Of <(T>)>) 파생 컬렉션을 직접 사용하는 LINQ쿼리를 말함
LINQ를 사용하여 List<(Of <(T>)>), Array 또는 Dictionary<(Of <(TKey, TValue>)>)와 같은 열거 가능한 컬렉션을 모두 쿼리가능

2.1. LINQ 및 문자열
문자열 및 문자열의 컬렉션을 쿼리하고 변환
일반적인 문자열 함수 및 정규식과 결합될 수 있다.

2.1.1 문자열에서 단어가 나오는 횟수 세기(LINQ)
 class CountWords
{
    static void Main()
    {
        string text = @"Historically, the world of data and the world of objects" +
          @" have not been well integrated. Programmers work in C# or Visual Basic" +
          @" and also in SQL or XQuery. On the one side are concepts such as classes," +
          @" objects, fields, inheritance, and .NET Framework APIs. On the other side" +
          @" are tables, columns, rows, nodes, and separate languages for dealing with" +
          @" them. Data types often require translation between the two worlds; there are" +
          @" different standard functions. Because the object world has no notion of query, a" +
          @" query can only be represented as a string without compile-time type checking or" +
          @" IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to" +
          @" objects in memory is often tedious and error-prone.";

        string searchTerm = "data";

        //Convert the string into an array of words
        string[] source = text.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries);

        // Create and execute the query. It executes immediately because a singleton value is produced. 즉시실행???
        // Use ToLowerInvariant to match "data" and "Data"
        var matchQuery = from word in source
                         where word.ToLowerInvariant() == searchTerm.ToLowerInvariant()
                         select word;

        // Count the matches.
        int wordCount = matchQuery.Count();
        Console.WriteLine("{0} occurrences(s) of the search term \"{1}\" were found.", wordCount, searchTerm);

    }
}
/* Output:
   3 occurrences(s) of the search term "data" were found.
*/

2.1.2 지정된 단어 집합이 들어 있는 문장 쿼리(LINQ)
//나눈 문장들에서 "Historically", "data" 및 "integrated"이라는 단어를 모두 포함한 문장을 반환.
        // Split the text block into an array of sentences.
        string[] sentences = text.Split(new char[] { '.', '?', '!' });

        // Define the search terms. This list could also be dynamically populated at runtime.
        string[] wordsToMatch = { "Historically", "data", "integrated" };

        // let에서 문장들 나누고, Distinct로 중복된 문장제거, Intersect로 교집합연산의 개수가 wordsToMatch의 개수와 동일한 문장만 Select
        // Note that the number of terms to match is not specified at compile time.
        var sentenceQuery = from sentence in sentences
                            let w = sentence.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' },StringSplitOptions.RemoveEmptyEntries)
                            where w.Distinct().Intersect(wordsToMatch).Count() == wordsToMatch.Count()
                            select sentence;
     
        // Execute the query. Note that you can explicitly type the iteration variable here even though sentenceQuery
        // was implicitly typed.
        foreach (string str in sentenceQuery)
        {
            Console.WriteLine(str);
        }
2.1.3 문자열의 문자 쿼리(LINQ)
String 클래스는 제네릭 IEnumerable<(Of <(T>)>) 인터페이스를 구현하기 때문에 모든 문자열을 문자 시퀀스로 쿼리할 수 있다.
class QueryAString
{
    static void Main()
    {
        string aString = "ABCDE99F-J74-12-89A";

        // Select only those characters that are numbers 숫자로~~
        IEnumerable<char> stringQuery =
          from ch in aString
          where Char.IsDigit(ch)
          select ch;

        // Execute the query
        foreach (char c in stringQuery)
            Console.Write(c + " ");

        // Call the Count method on the existing query.
        int count = stringQuery.Count();
        Console.WriteLine("Count = {0}", count);

        // Select all characters before the first '-'
        IEnumerable<char> stringQuery2 = aString.TakeWhile(c => c != '-');

        // Execute the second query
        foreach (char c in stringQuery2)
            Console.Write(c);

        Console.WriteLine(System.Environment.NewLine + "Press any key to exit");
        Console.ReadKey();

    }
}
/* Output:
  Output: 9 9 7 4 1 2 8 9
  Count = 8
  ABCDE99F
*/

2.1.4. LINQ 쿼리와 정규식 결합
Regex 클래스를 사용하여 텍스트 문자열에서 좀 더 복잡한 비교를 위해 정규식을 만드는 방법
class QueryWithRegEx
{
     // This method assumes that the application has discovery permissions for all folders under the specified path.
    static IEnumerable<System.IO.FileInfo> GetFiles(string path)
    {
        if (!System.IO.Directory.Exists(path))
            throw new System.IO.DirectoryNotFoundException();

        string[] fileNames = null;
        List<System.IO.FileInfo> files = new List<System.IO.FileInfo>();

        fileNames = System.IO.Directory.GetFiles(path, "*.*", System.IO.SearchOption.AllDirectories);
        foreach (string name in fileNames)
        {
            files.Add(new System.IO.FileInfo(name));
        }
        return files;
    }
    public static void Main()
    {
        // Modify this path as necessary.
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";

        // Take a snapshot of the file system.
        IEnumerable<System.IO.FileInfo> fileList = GetFiles(startFolder); //폴더의 모든 파일정보

        // Create the regular expression to find all things "Visual".
        System.Text.RegularExpressions.Regex searchTerm =
            new System.Text.RegularExpressions.Regex(@"Visual (Basic|C#|C\+\+|J#|SourceSafe|Studio)");

        // Search the contents of each .htm file.
        // Remove the where clause to find even more matches!
        // This query produces a list of files where a match was found, and a list of the matches in that file.
        // Note: Explicit typing of "Match" in select clause.
        // This is required because MatchCollection is not a generic IEnumerable collection.
        var queryMatchingFiles =
            from file in fileList
            where file.Extension == ".htm" //확장자가 htm인 것들중에
            let fileText = System.IO.File.ReadAllText(file.FullName) // 파일명만 fileText 목록(집합)으로두고
            let matches = searchTerm.Matches(fileText) // fileText에서 searchTerm에 해당하는 것들만
            where searchTerm.Matches(fileText).Count > 0 //이게 없으면 matches에 null도 들어가나??? 확인필요
            select new
            {
                name = file.FullName,
                matches = from System.Text.RegularExpressions.Match match in matches
                          select match.Value
            };

        // Execute the query.
        Console.WriteLine("The term \"{0}\" was found in:", searchTerm.ToString());

        foreach (var v in queryMatchingFiles)
        {
            // Trim the path a bit, then write the file name in which a match was found.
            string s = v.name.Substring(startFolder.Length - 1);
            Console.WriteLine(s);

            // For this file, write out all the matching strings
            foreach (var v2 in v.matches)
            {
                Console.WriteLine("  " + v2);
            }
        }
    } 
}
2.1.5. 두 목록 간의 차집합 구하기(LINQ)
 names1.txt에 있지만 names2.txt에는 없는 해당 줄을 출력
class CompareLists
{       
    static void Main()
    {
        // Create the IEnumerable data sources.
        string[] names1 = System.IO.File.ReadAllLines(@"../../../names1.txt");
        string[] names2 = System.IO.File.ReadAllLines(@"../../../names2.txt");

        // Create the query. Note that method syntax must be used here.
        IEnumerable<string> differenceQuery =
          names1.Except(names2);

        // Execute the query.
        Console.WriteLine("The following lines are in names1.txt but not names2.txt");
        foreach (string s in differenceQuery)
            Console.WriteLine(s);
    }
}
2.1.6. 단어 또는 필드에 따라 텍스트 데이터 정렬 또는 필터링(LINQ)
쉼표로 구분된 값과 같은 구조화된 텍스트 줄을 해당 줄에서 임의의 필드를 기준으로 정렬하는 방법
scores.csv의 필드는 학생의 ID 번호와 4개의 테스트 점수를 나타낸다고 가정
public class SortLines
{
    static void Main()
    {
        // Create an IEnumerable data source
        string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv");

        // Change this to any value from 0 to 4.
        int sortField = 1; //두번째 필드 말하죠.. (0부터시작)

        Console.WriteLine("Sorted highest to lowest by field [{0}]:", sortField);

        // Demonstrates how to return query from a method.
        // The query is executed here.
        foreach (string str in RunQuery(scores, sortField))
        {
            Console.WriteLine(str);
        }
    }

    // Returns the query variable, not query results!
    static IEnumerable<string> RunQuery(IEnumerable<string> source, int num)
    {
        // Split the string and sort on field[num]
        var scoreQuery = from line in source
                         let fields = line.Split(',')
                         orderby fields[num] descending
                         select line;

        return scoreQuery;
    }
}
/* Output (if sortField == 1):
   Sorted highest to lowest by field [1]:
    116, 99, 86, 90, 94
    120, 99, 82, 81, 79
    111, 97, 92, 81, 60
    114, 97, 89, 85, 82
    121, 96, 85, 91, 60
    122, 94, 92, 91, 91
    117, 93, 92, 80, 87
    118, 92, 90, 83, 78
    113, 88, 94, 65, 91
    112, 75, 84, 91, 39
    119, 68, 79, 88, 92
    115, 35, 72, 91, 70
 */
2.1.7. 구분된 파일의 필드 다시 정렬후 파일로 저장.
- spreadsheet1.csv라는 일반 텍스트 내용
Adams,Terry,120
Fakhouri,Fadi,116
Feng,Hanying,117
Garcia,Cesar,114
Garcia,Debra,115
Garcia,Hugo,118
Mortensen,Sven,113
O'Donnell,Claire,112
Omelchenko,Svetlana,111
Tucker,Lance,119
Tucker,Michael,122
Zabokritski,Eugene,121

-파일을 읽어 쉼표로 구분하고,  3번쨰 필드로 정렬한 후 다시 파일로 저장
        // Create the IEnumerable data source
        string[] lines = System.IO.File.ReadAllLines(@"../../../spreadsheet1.csv");

        // Create the query. Put field 2 first, then
        // reverse and combine fields 0 and 1 from the old field
        IEnumerable<string> query =
            from line in lines
            let x = line.Split(',')
            orderby x[2] 
            select x[2] + ", " + (x[1] + " " + x[0]);

        // Execute the query and write out the new file. Note that WriteAllLines
        // takes a string[], so ToArray is called on the query.
        System.IO.File.WriteAllLines(@"../../../spreadsheet2.csv", query.ToArray());

2.1.7. 문자열 컬렉션 결합 및 비교
텍스트 줄이 포함된 파일을 병합한 다음 결과를 정렬하는 방법
특히 두 개의 텍스트 줄 집합에서의 간단한 연결, 공용 구조체 및 교집합을 수행
- names1.txt 내용
Bankov, Peter
Holm, Michael
Garcia, Hugo
Potra, Cristina
Noriega, Fabricio
Aw, Kam Foo
Beebe, Ann
Toyoshima, Tim
Guy, Wey Yuan
Garcia, Debra
- names2.txt 내용
Liu, Jinghao
Bankov, Peter
Holm, Michael
Garcia, Hugo
Beebe, Ann
Gilchrist, Beth
Myrcha, Jacek
Giakoumakis, Leo
McLin, Nkenge
El Yassir, Mehdi

        static void OutputQueryResults(IEnumerable<string> query, string message)
        {
            Console.WriteLine(System.Environment.NewLine + message);
            foreach (string item in query)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("{0} total names in list", query.Count());
        }
//위 함수가 미리 정의돼 있다고 가정
            //Put text files in your solution folder
            string[] fileA = System.IO.File.ReadAllLines(@"../../../names1.txt");
            string[] fileB = System.IO.File.ReadAllLines(@"../../../names2.txt");

            //Simple concatenation and sort. Duplicates are preserved.
            IEnumerable<string> concatQuery = fileA.Concat(fileB).OrderBy(s => s);

            // Pass the query variable to another function for execution.
            OutputQueryResults(concatQuery, "Simple concatenate and sort. Duplicates are preserved:");

            // Concatenate and remove duplicate names based on default string comparer.(병합)
            IEnumerable<string> uniqueNamesQuery =
                fileA.Union(fileB).OrderBy(s => s); //병합하면서 distinct도 될터
            OutputQueryResults(uniqueNamesQuery, "Union removes duplicate names:");

            // Find the names that occur in both files (based on default string comparer). (교집합)
            IEnumerable<string> commonNamesQuery =
                fileA.Intersect(fileB);
            OutputQueryResults(commonNamesQuery, "Merge based on intersect:");

            // Find the matching fields in each list. Merge the two results by using Concat,
            // and then
sort using the default string comparer.
            string nameMatch = "Garcia";

            IEnumerable<String> tempQuery1 =
                from name in fileA
                let n = name.Split(',')
                where n[0] == nameMatch //,로 분리후 0번필드중에  nameMatch와 일치하는  것들 

                select name;

            IEnumerable<string> tempQuery2 =
                from name2 in fileB
                let n2 = name2.Split(',')
                where n2[0] == nameMatch
                select name2;

            IEnumerable<string> nameMatchQuery =
                tempQuery1.Concat(tempQuery2).OrderBy(s => s); // 이러면 union효과가 되나? 아님 Left join?? 확인필요
            OutputQueryResults(nameMatchQuery, String.Format("Concat based on partial name match \"{0}\":", nameMatch));

2.1.8. 여러 소스로 개체 컬렉션 채우기(두 파일읽어서 조인효과 구현)
- scores.csv
111, 97, 92, 81, 60
112, 75, 84, 91, 39
113, 88, 94, 65, 91
114, 97, 89, 85, 82
115, 35, 72, 91, 70
116, 99, 86, 90, 94
117, 93, 92, 80, 87
118, 92, 90, 83, 78
119, 68, 79, 88, 92
120, 99, 82, 81, 79
121, 96, 85, 91, 60
122, 94, 92, 91, 91
- names.csv
Omelchenko,Svetlana,111
O'Donnell,Claire,112
Mortensen,Sven,113
Garcia,Cesar,114
Garcia,Debra,115
Fakhouri,Fadi,116
Feng,Hanying,117
Garcia,Hugo,118
Tucker,Lance,119
Adams,Terry,120
Zabokritski,Eugene,121
Tucker,Michael,122
        // These data files are defined in How to: Join Content from Dissimilar Files (LINQ)
        string[] names = System.IO.File.ReadAllLines(@"../../../names.csv");
        string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv");

        // Merge the data sources using a named type.
        // var could be used instead of an explicit type.
        // Note the dynamic creation of a list of ints for the TestScores member. We skip 1 because the first string
        // in the array is the student ID, not an exam score.
        IEnumerable<Student> queryNamesScores =
            from name in names
            let x = name.Split(',')
            from score in scores
            let s = score.Split(',')
            where x[2] == s[0]  // score의 첫번째 컬럼과 names의 두번째 컬럼과 조인(학생ID)
            select new Student()  //이렇게 새로운 타입으로 new
            {
                FirstName = x[0],
                LastName = x[1],
                ID = Convert.ToInt32(x[2]), //타입명시 
                ExamScores = (from scoreAsText in s.Skip(1) //첫번째 값은 ID이므로 skip 
                              select Convert.ToInt32(scoreAsText)).
                              ToList()
            };

        // Optional. Store the newly created student objects in memory for faster access in future queries. Could be useful with
        // very large data files.
        List<Student> students = queryNamesScores.ToList();

        // Display the results and perform one further calculation.
        foreach (var student in students)
        {
            Console.WriteLine("The average score of {0} {1} is {2}.",
                student.FirstName, student.LastName, student.ExamScores.Average());
        }
2.1.9. 그룹을 사용하여 파일을 여러 파일로 분할
- names1.csv
Bankov, Peter
Holm, Michael
Garcia, Hugo
Potra, Cristina
Noriega, Fabricio
Aw, Kam Foo
Beebe, Ann
Toyoshima, Tim
Guy, Wey Yuan
Garcia, Debra
- names2.csv
Liu, Jinghao
Bankov, Peter
Holm, Michael
Garcia, Hugo
Beebe, Ann
Gilchrist, Beth
Myrcha, Jacek
Giakoumakis, Leo
McLin, Nkenge
El Yassir, Mehdi

        string[] fileA = System.IO.File.ReadAllLines(@"../../../names1.txt");
        string[] fileB = System.IO.File.ReadAllLines(@"../../../names2.txt");

        // Concatenate and remove duplicate names based on default string comparer
        var mergeQuery = fileA.Union(fileB);

        // Group the names by the first letter in the last name.
        var groupQuery = from name in mergeQuery
                         let n = name.Split(',')
                         group name by n[0][0] into g  //제일 첫글자 , n[0]은 첫번쨰 컬럼
                         orderby g.Key
                         select g;

        // Create a new file for each group that was created
        // Note that nested foreach loops are required to access
        // individual items with each group.
        foreach (var g in groupQuery)
        {
            // Create the new file name.
            string fileName = @"../../../testFile_" + g.Key + ".txt";
            // Write file. 그룹별로 파일생성
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter(fileName))
            {
                foreach (var item in g)
                {
                    sw.WriteLine(item);
                    // Output to console for example purposes.
                    Console.WriteLine("   {0}", item);
                }
            }
        }

2.1.10. 서로 다른 파일의 콘텐츠 조인 
코드만 봐도 될듯
        string[] names = System.IO.File.ReadAllLines(@"../../../names.csv");
        string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv");
        // Name:    Last[0],                First[1],      ID[2],     Grade Level[3]
        //                  Omelchenko,    Svetlana,      11,          2
        // Score:   StudentID[0],  Exam1[1]   Exam2[2],  Exam3[3],  Exam4[4]
        //          111,           97,        92,        81,        60

        // This query joins two dissimilar spreadsheets based on common ID value.
        // Multiple from clauses are used instead of a join clause
        // in order to store results of id.Split.
        IEnumerable<string> scoreQuery1 =
            from name in names
            let nameFields = name.Split(',')
            from id in scores
            let scoreFields = id.Split(',')
            where nameFields[2] == scoreFields[0]
            select nameFields[0] + "," + scoreFields[1] + "," + scoreFields[2]
                   + "," + scoreFields[3] + "," + scoreFields[4];

        // Pass a query variable to a method and
        // execute it in the method. The query itself
        // is unchanged.
        OutputQueryResults(scoreQuery1, "Merge two spreadsheets:");

2.1.10. CSV 텍스트 파일의 열 값 계산 

         string[] lines = System.IO.File.ReadAllLines(@"../../../scores.csv");
          .....
        IEnumerable<IEnumerable<int>> query = from line in strs
            let x = line.Split(',')
            let y = x.Skip(1)
            select (
                            from str in y
                            select Convert.ToInt32(str));

        // Execute and cache the results for performance.
        // ToArray could also be used here.
        var results = query.ToList();

        // Find out how many columns we have.
        int columnCount = results[0].Count();

        // Perform aggregate calculations on each column.           
        // One loop for each score column in scores.
        // We can use a for loop because we have already executed the columnQuery in the call to ToList.
        for (int column = 0; column < columnCount; column++)
        {
            var res2 = from row in results
                       select row.ElementAt(column);

            double average = res2.Average(); //컬럼에 대한 average
            int max = res2.Max();
            int min = res2.Min();

            // 1 is added to column because Exam numbers
            // begin with 1
            Console.WriteLine("Exam #{0} Average: {1:##.##} High Score: {2} Low Score: {3}",
                          column + 1, average, max, min);
        }

2.2. LINQ 및 리플렉션
LINQ를 리플렉션과 함께 사용하여 지정한 검색 조건에 일치하는 메서드에 대한 특정 메타데이터를 검색할 수 있다

using System.Reflection;
using System.IO;
namespace LINQReflection
{
    class ReflectionHowTO
    {
        static void Main(string[] args)
        {
            Assembly assembly = Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken= b77a5c561934e089");
            var pubTypesQuery = 
            from type in assembly.GetTypes() // 타입목록 추출
            where type.IsPublic
            from method in type.GetMethods() // 각 타입에서 메소드목록 추출
            where method.ReturnType.IsArray == true 
                      || ( method.ReturnType.GetInterface(typeof(System.Collections.Generic.IEnumerable<>).FullName ) != null
                     && method.ReturnType.FullName != "System.String" )
            group method.ToString() by type.ToString();
            // 이렇게 되면 타입콜렉션의 속성으로 method가 들어가는 형태임. 아래에서 키(콜렉션 내에서 타입을 식별하는)별로 메소드 출력
            foreach (var groupOfMethods in pubTypesQuery)
            {
                Console.WriteLine("Type: {0}", groupOfMethods.Key);
                foreach (var method in groupOfMethods)
                {
                    Console.WriteLine("  {0}", method);
                }
            }

            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }
    } 
}

2.3. LINQ 및 파일 디렉터리
문자열을 다루면서 파일에 관련된 내용이 나오긴 했지만 여기에서 더 상세히 다룸.

2.1.1. 지정된 특성 또는 이름을 갖는 파일 쿼리 
//주어진 경로의 파일정보 가져오는 함수  
// This method assumes that the application has discovery  permissions for all folders under the specified path.
    static IEnumerable<System.IO.FileInfo> GetFiles(string path)
    {
        if (!System.IO.Directory.Exists(path))
            throw new System.IO.DirectoryNotFoundException();

        string[] fileNames = null;
        List<System.IO.FileInfo> files = new List<System.IO.FileInfo>();

        fileNames = System.IO.Directory.GetFiles(path, "*.*", System.IO.SearchOption.AllDirectories);           
        foreach (string name in fileNames)
        {
            files.Add(new System.IO.FileInfo(name));
        }
        return files;
    }
...
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";

        // Take a snapshot of the file system.
        IEnumerable<System.IO.FileInfo> fileList = GetFiles(startFolder);

        //Create the query
        IEnumerable<System.IO.FileInfo> fileQuery =
            from file in fileList
            where file.Extension == ".txt"
            orderby file.Name
            select file;

        //Execute the query. This might write out a lot of files!
        foreach (System.IO.FileInfo fi in fileQuery)         
             Console.WriteLine(fi.FullName);    // Create and execute a new query by using the previous
        // query as a starting point. fileQuery is not
        // executed again until the call to Last()
        var newestFile =
            (from file in fileQuery
            orderby file.CreationTime
            select new { file.FullName, file.CreationTime })
            .Last();

        Console.WriteLine("\r\nThe newest .txt file is {0}. Creation time: {1}",
            newestFile.FullName, newestFile.CreationTime);

2.1.2. 확장명에 따라 파일 그룹화 

        // Take a snapshot of the file system.
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\Common7";

        // Used in WriteLine to trim output lines.
        int trimLength = startFolder.Length;

        // Take a snapshot of the file system.
        IEnumerable<System.IO.FileInfo> fileList = GetFiles(startFolder);

        // Create the query.
        var queryGroupByExt =
            from file in fileList
            group file by file.Extension.ToLower() into fileGroup
            orderby fileGroup.Key //그루핑이 되면서 동일그룹에 키값들이 할당됨에 유의
            select fileGroup;
      PageOutput(trimLength, queryGroupByExt); // 바로아래에 정의

   private static void PageOutput( int rootLength,
                                    IEnumerable<System.Linq.IGrouping<string, System.IO.FileInfo>> groupByExtList)
    {
        // Flag to break out of paging loop.
        bool goAgain = true;

        // "3" = 1 line for extension + 1 for "Press any key" + 1 for input cursor.
        int numLines = Console.WindowHeight - 3;

        // Iterate through the outer collection of groups.
        foreach (var filegroup in groupByExtList)
        {
            // Start a new extension at the top of a page.
            int currentLine = 0;

            // Output only as many lines of the current group as will fit in the window.
            do
            {
                Console.Clear();
                Console.WriteLine(filegroup.Key == String.Empty ? "[none]" : filegroup.Key);

                // Get 'numLines' number of items starting at number 'currentLine'.
                var resultPage = filegroup.Skip(currentLine).Take(numLines);

                //Execute the resultPage query
                foreach (var f in resultPage)
                {
                    Console.WriteLine("\t{0}", f.FullName.Substring(rootLength));
                }

                // Increment the line counter.
                currentLine += numLines;

                // Give the user a chance to escape.
                Console.WriteLine("Press any key to continue or the 'End' key to break...");
                ConsoleKey key = Console.ReadKey().Key;
                if (key == ConsoleKey.End)
                {
                    goAgain = false;
                    break;
                }
            } while (currentLine < filegroup.Count());

            if (goAgain == false)
                break;
        }
    }
2.1.3. 폴더 집합의 전체 바이트 수 쿼리
    static long GetFileLength(string filename)
    {
        long retval;
        try { System.IO.FileInfo fi = new System.IO.FileInfo(filename);
            retval = fi.Length;
        }
        catch (System.IO.FileNotFoundException)
        {
            // If a file is no longer present,
            // just add zero bytes to the total.
            retval = 0;
        }
        return retval;
    }
.....
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\VC#";

        // Take a snapshot of the file system.
        // This method assumes that the application has discovery permissions
        // for all folders under the specified path.
        IEnumerable<string> fileList = System.IO.Directory.GetFiles(startFolder, "*.*", System.IO.SearchOption.AllDirectories);

        var fileQuery = from file in fileList
                        select GetFileLength(file);

        // Cache the results to avoid multiple trips to the file system.
        long[] fileLengths = fileQuery.ToArray();

        // Return the size of the largest file
        long largestFile = fileLengths.Max();

        // Return the total number of bytes in all the files under the specified folder.
        long totalBytes = fileLengths.Sum();

        Console.WriteLine("There are {0} bytes in {1} files under {2}",
            totalBytes, fileList.Count(), startFolder);
        Console.WriteLine("The largest files is {0} bytes.", largestFile);
2.1.3. 두 폴더의 내용 비교
세 가지 방법
- 두 개의 파일 목록이 동일한지 여부를 지정하는 부울 값 쿼리
- 양쪽 파일에 있는 파일을 검색하는 교차 부분 쿼리
- 한 폴더에는 있지만 다른 폴더에는 없는 파일을 검색하는 차집합 쿼리

    class FileCompare : System.Collections.Generic.IEqualityComparer<System.IO.FileInfo>
    {
        public FileCompare() { }

        public bool Equals(System.IO.FileInfo f1, System.IO.FileInfo f2)
        {
            return (f1.Name == f2.Name && f1.Length == f2.Length); //파일명과 길이비교
        }

        // Return a hash that reflects the comparison criteria. According to the
        // rules for IEqualityComparer<T>, if Equals is true, then the hash codes must
        // also be equal. Because equality as defined here is a simple value equality, not
        // reference identity, it is possible that two or more objects will produce the same
        // hash code.
        public int GetHashCode(System.IO.FileInfo fi)
        {
            string s = String.Format("{0}{1}", fi.Name, fi.Length);
            return s.GetHashCode();
        }
    }
라는 Compare클래스 미리정의 된 경우
            string pathA = @"C:\TestDir";
            string pathB = @"C:\TestDir2"; // Take a snapshot of the file system.
            IEnumerable<System.IO.FileInfo> list1 = GetFiles(pathA);
            IEnumerable<System.IO.FileInfo> list2 = GetFiles(pathB);

            //A custom file comparer defined below
            FileCompare myFileCompare = new FileCompare();

            // This query determines whether the two folders contain identical file lists, based on the custom file comparer
            // that is defined in the FileCompare class.
            // The query executes immediately because it returns a bool.
            bool areIdentical = list1.SequenceEqual(list2, myFileCompare);
            if (areIdentical == true)
                Console.WriteLine("the two folders are the same");
            else
                Console.WriteLine("The two folders are not the same");

            // Find the common files. It produces a sequence and doesn't execute until the foreach statement.
            var queryCommonFiles = list1.Intersect(list2, myFileCompare);
           if (queryCommonFiles.Count() > 0)
           {
                Console.WriteLine("The following files are in both folders:");
                foreach (var v in queryCommonFiles)
                {
                    Console.WriteLine(v.FullName); //shows which items end up in result list
                }
            }
            else
            {
                Console.WriteLine("There are no common files in the two folders.");
            }

            // Find the set difference between the two folders.
            // For this example we only check one way.
            var queryList1Only = (from file in list1 select file).Except(list2, myFileCompare);

            Console.WriteLine("The following files are in list1 but not list2:");
            foreach (var v in queryList1Only)
            {
                Console.WriteLine(v.FullName);
            }
2.1.4. 디렉터리 트리에서 가장 큰 파일을 하나 이상 쿼리 
파일 크기(바이트)와 관련된 5개의 쿼리방법
- 가장 큰 파일의 크기(바이트)를 검색하는 방법
- 가장 작은 파일의 크기(바이트)를 검색하는 방법
- 지정한 루트 폴더에 있는 하나 이상의 폴더에서 FileInfo 개체의 가장 큰 파일이나 가장 작은 파일을 검색하는 방법
- 가장 큰 10개 파일과 같은 시퀀스를 검색하는 방법
- 지정한 크기보다 작은 파일을 무시하여 파일 크기(바이트)에 따라 파일을 그룹으로 정렬하는 방법
       string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";

        // Take a snapshot of the file system.
        // fileList is an IEnumerable<System.IO.FileInfo>
        var fileList = GetFiles(startFolder);

        //Return the size of the largest file
        long maxSize =
            (from file in fileList
             let len = GetFileLength(file)
             select len).Max();

        Console.WriteLine("The length of the largest file under {0} is {1}",
            startFolder, maxSize);

        // Return the FileInfo object for the largest file by sorting and selecting from beginning of list
        System.IO.FileInfo longestFile =
            (from file in fileList
            let len = GetFileLength(file)
            where len > 0
            orderby len descending
            select file).First();

        Console.WriteLine("The largest file under {0} is {1} with a length of {2} bytes",
                            startFolder, longestFile.FullName, longestFile.Length);

        //Return the FileInfo of the smallest file
        System.IO.FileInfo smallestFile =
            (from file in fileList
            let len = GetFileLength(file)
            where len > 0
            orderby len ascending
            select file).First();

        Console.WriteLine("The smallest file under {0} is {1} with a length of {2} bytes",
                            startFolder, smallestFile.FullName, smallestFile.Length);

        //Return the FileInfos for the 10 largest files queryTenLargest is an IEnumerable<System.IO.FileInfo>
        var queryTenLargest =
            (from file in fileList
            let len = GetFileLength(file)
            orderby len descending
            select file).Take(10);

        Console.WriteLine("The 10 largest files under {0} are:", startFolder);

        foreach (var v in queryTenLargest)
        {
            Console.WriteLine("{0}: {1} bytes", v.FullName, v.Length);
        }


        // Group the files according to their size, leaving out files that are less than 200000 bytes.
        var querySizeGroups =
            from file in fileList
            let len = GetFileLength(file)
            where len > 0
            group file by (len / 100000) into fileGroup
            where fileGroup.Key >= 2
            orderby fileGroup.Key descending
            select fileGroup;


        foreach (var filegroup in querySizeGroups)
        {
            Console.WriteLine(filegroup.Key.ToString() + "00000");
            foreach (var item in filegroup)
            {
                Console.WriteLine("\t{0}: {1}", item.Name, item.Length);
            }
        }

2.1.5. 디렉터리 트리의 중복 파일 쿼리
 첫 번째 쿼리에서는 간단한 키를 사용하여 일치하는 항목을 확인(이름은 같지만 내용은 다를 수 있는 파일임)
 두 번째 쿼리에서는 복합 키를 사용하여 FileInfo 개체의 세 가지 속성에 대한 일치 여부를 확인
class QueryDuplicateFileNames
{
    static void Main(string[] args)
    {  
        // Uncomment QueryDuplicates2 to run that query.
        QueryDuplicates();           
        // QueryDuplicates2();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    static void QueryDuplicates()
    {
        // Change the root drive or folder if necessary
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";

        // Take a snapshot of the file system.
        IEnumerable<System.IO.FileInfo> fileList = GetFiles(startFolder);

        // used in WriteLine to keep the lines shorter
        int charsToSkip = startFolder.Length;

        // var can be used for convenience with groups.
        var queryDupNames =
            from file in fileList
            group file.FullName.Substring(charsToSkip) by file.Name into fileGroup
            where fileGroup.Count() > 1
            select fileGroup;

        // Pass the query to a method that will
        // output one page at a time.
        PageOutput<string,string>(queryDupNames);
    }

    // A Group key that can be passed to a separate method.
    // Override Equals and GetHashCode to define equality for the key.
    // Override ToString to provide a friendly name for Key.ToString()
    class PortableKey
    {
        public string Name { get; set; }
        public DateTime CreationTime { get; set; }
        public long Length {get;  set;}

        public override bool Equals(object obj)
        {
            PortableKey other = (PortableKey)obj;
            return other.CreationTime == this.CreationTime &&
                   other.Length == this.Length &&
                   other.Name == this.Name;
        }

        public override int GetHashCode()
        {
            string str = String.Format("{0}{1}{2}", this.CreationTime, this.Length, this.Name);
            return str.GetHashCode();
        }
        public override string ToString()
        {
            return String.Format("{0} {1} {2}", this.Name, this.Length, this.CreationTime);
        }
    }
    static void QueryDuplicates2()
    {
        // Change the root drive or folder if necessary.
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\Common7";

        // Make the the lines shorter for the console display
        int charsToSkip = startFolder.Length;

        // Take a snapshot of the file system.
        IEnumerable<System.IO.FileInfo> fileList = GetFiles(startFolder);

        // Note the use of a compound key. Files that match
        // all three properties belong to the same group.
        // A named type is used to enable the query to be
        // passed to another method. Anonymous types can also be used
        // for composite keys but cannot be passed across method boundaries
        //
        var queryDupFiles =
            from file in fileList
            group file.FullName.Substring(charsToSkip) by
                new PortableKey{ Name=file.Name, CreationTime=file.CreationTime, Length=file.Length } into fileGroup
            where fileGroup.Count() > 1

            select fileGroup;

        var list = queryDupFiles.ToList();

        int i = queryDupFiles.Count();

        PageOutput<PortableKey, string>(queryDupFiles);              
    }


    // A generic method to page the output of the QueryDuplications methods
    // Here the type of the group must be specified explicitly. "var" cannot
    // be used in method signatures. This method does not display more than one
    // group per page.
    private static void PageOutput<K,V>(IEnumerable<System.Linq.IGrouping<K, V>> groupByExtList)
    {
        // Flag to break out of paging loop.
        bool goAgain = true;

        // "3" = 1 line for extension + 1 for "Press any key" + 1 for input cursor.
        int numLines = Console.WindowHeight - 3;

        // Iterate through the outer collection of groups.
        foreach (var filegroup in groupByExtList)
        {
            // Start a new extension at the top of a page.
            int currentLine = 0;

            // Output only as many lines of the current group as will fit in the window.
            do
            {
                Console.Clear();
                Console.WriteLine("Filename = {0}", filegroup.Key.ToString() == String.Empty ? "[none]" : filegroup.Key.ToString());

                // Get 'numLines' number of items starting at number 'currentLine'.
                var resultPage = filegroup.Skip(currentLine).Take(numLines);

                //Execute the resultPage query
                foreach (var fileName in resultPage)
                {
                    Console.WriteLine("\t{0}", fileName);
                }

                // Increment the line counter.
                currentLine += numLines;

                // Give the user a chance to escape.
                Console.WriteLine("Press any key to continue or the 'End' key to break...");
                ConsoleKey key = Console.ReadKey().Key;
                if (key == ConsoleKey.End)
                {
                    goAgain = false;
                    break;
                }
            } while (currentLine < filegroup.Count());

            if (goAgain == false)
                break;
        }
    }


    // This method assumes that the application has discovery
    // permissions for all folders under the specified path.
    static IEnumerable<System.IO.FileInfo> GetFiles(string path)
    {
        if (!System.IO.Directory.Exists(path))
            throw new System.IO.DirectoryNotFoundException();

        string[] fileNames = null;
        List<System.IO.FileInfo> files = new List<System.IO.FileInfo>();

        fileNames = System.IO.Directory.GetFiles(path, "*.*", System.IO.SearchOption.AllDirectories);
        foreach (string name in fileNames)
        {
            files.Add(new System.IO.FileInfo(name));
        }
        return files;
    }
}

2.1.6. 폴더의 파일 내용 쿼리  

        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";

        // Take a snapshot of the file system.
        IEnumerable<System.IO.FileInfo> fileList = GetFiles(startFolder);

        string searchTerm = @"Visual Studio";

        // Search the contents of each file.
        // A regular expression created with the RegEx class
        // could be used instead of the Contains method.
        // queryMatchingFiles is an IEnumerable<string>.
        var queryMatchingFiles =
            from file in fileList
            where file.Extension == ".htm"
            let fileText = GetFileText(file.FullName)
            where fileText.Contains(searchTerm)
            select file.FullName;

        // Execute the query.
        Console.WriteLine("The term \"{0}\" was found in:", searchTerm);
        foreach (string filename in queryMatchingFiles)
        {
            Console.WriteLine(filename);
        }

3. LINQ to XML
http://msdn.microsoft.com/ko-kr/library/bb387098.aspx
DOM(문서 개체 모델) XML 프로그래밍 인터페이스와 유사.
LINQ to XML의 쿼리 기능은 기능 면에서(구문 면에서는 아니지만) XPath 및 XQuery와 유사.
클래스들

3.1. LINQ to XML과 DOM 비교
LINQ to XML과 현재 주로 사용되는 XML 프로그래밍 API인 W3C DOM(문서 개체 모델)의 몇 가지 주요 차이점

3.1.1. W3C DOM에서는 상향식으로 XML 트리를 빌드. 즉, 문서를 만들고 요소를 만든 다음 요소를 문서에 아래코드와 같이 추가 하는 형식이지만
LINQ to XML에서 함수 생성을 사용하여 훨씬 직관적인 코드를 생성할 수 있다.
 예) DOM의 Microsoft 구현인 XmlDocument를 사용하여 XML 트리를 만드는 일반적인 방법
XmlDocument doc = new XmlDocument();
XmlElement name = doc.CreateElement("Name");
name.InnerText = "Patrick Hines";
XmlElement phone1 = doc.CreateElement("Phone");
phone1.SetAttribute("Type", "Home");
phone1.InnerText = "206-555-0144";       
XmlElement phone2 = doc.CreateElement("Phone");
phone2.SetAttribute("Type", "Work");
phone2.InnerText = "425-555-0145";       
XmlElement street1 = doc.CreateElement("Street1");       
street1.InnerText = "123 Main St";
XmlElement city = doc.CreateElement("City");
city.InnerText = "Mercer Island";
XmlElement state = doc.CreateElement("State");
state.InnerText = "WA";
XmlElement postal = doc.CreateElement("Postal");
postal.InnerText = "68042";
XmlElement address = doc.CreateElement("Address");
address.AppendChild(street1);
address.AppendChild(city);
address.AppendChild(state);
address.AppendChild(postal);
XmlElement contact = doc.CreateElement("Contact");
contact.AppendChild(name);
contact.AppendChild(phone1);
contact.AppendChild(phone2);
contact.AppendChild(address);
XmlElement contacts = doc.CreateElement("Contacts");
contacts.AppendChild(contact);
doc.AppendChild(contacts);
이 코딩 스타일은 XML 트리의 구조에 대한 많은 정보를 시각적으로 제공하지 않는다.
LINQ to XML에서는 이러한 XML 트리 생성 방법을 지원하며 추가적으로 다음과 같이
함수 생성에서는 XElement 및 XAttribute 생성자를 사용하여 XML 트리를 빌드하는 방법을 제공

비교) LINQ to XML에서 함수 생성을 사용하여 동일한 XML 트리를 생성하는 방법
XElement contacts =
    new XElement("Contacts",
        new XElement("Contact",
            new XElement("Name", "Patrick Hines"),
            new XElement("Phone", "206-555-0144",
                new XAttribute("Type", "Home")),
            new XElement("phone", "425-555-0145",
                new XAttribute("Type", "Work")),
            new XElement("Address",
                new XElement("Street1", "123 Main St"),
                new XElement("City", "Mercer Island"),
                new XElement("State", "WA"),
                new XElement("Postal", "68042")
            )
        )
    );
3.1.2 LINQtoXML에서는  바로 위 코드와 같이  LINQ XML 요소(XElement)로 직접 XML핸들링이 가능하다.
XML 파일에서 T:System.Xml.Linq.XElement 개체를 직접 로드도 가능
T:System.Xml.Linq.XElement 개체를 파일이나 스트림으로 serialize가능


반면에 W3C DOM에서는 아래코드와 같이 XML 문서가 XML 트리의 논리 컨테이너로 사용
XmlDocument doc = new XmlDocument();
XmlElement name = doc.CreateElement("Name");
name.InnerText = "Patrick Hines";
doc.AppendChild(name);
여러 문서에서 요소를 사용하려면 여러 문서의 노드를 가져와야 하지만 LINQ to XML에서는 이러한 복잡한 작업이 필요 없다.
LINQ to XML을 사용할 때 문서의 루트 수준에서 주석이나 처리 명령을 추가하려는 경우에만 XDocument 클래스를 사용.

3.1.3 LINQ to XML에서는 이름 및 네임스페이스의 처리가 간단하다.
기존 DOM 프로그래밍에서는 이름, 네임스페이스 및 네임스페이스 접두사의 처리는 XML 프로그래밍의 복잡한 부분.
LINQ to XML에서는 네임스페이스 접두사를 처리하는 요구 사항을 제거하여 이름과 네임스페이스를 단순화.
네임스페이스 접두사를 제어할 수 있다.
네임스페이스 접두사를 명시적으로 제어하지 않을경우
LINQ to XML에서는 serialize할 때 네임스페이스 접두사를 할당하거나, 기본 네임스페이스를 사용하여 serialize해야한다.
기본 네임스페이스가 사용되는 경우 생성되는 문서에는 네임스페이스 접두사가 없다.
기존 DOM 프로그래밍 방식에서는 노드의 이름을 변경할 수 없다.
대신 새 노드를 만들고 모든 자식 노드를 새 노드에 복사해야 하므로 원래 노드 ID가 손실됩니다.
LINQ to XML에서는 노드에서 XName 속성을 설정할 수 있도록 하여 이 문제를 방지합니다.

3.1.3.1. XML 네임스페이스 작업(네임스페이스 접두사 제어)
 LINQ to XML에서 XML 이름을 나타내는 클래스는 XName
 - 네임스페이스를 사용하여 문서 만들기(C#)(LINQ to XML)

 예1) 네임스페이스가 하나 포함된 문서를생성. 기본적으로 LINQ to XML은 기본 네임스페이스를 사용하여 이 문서를 serialize
  // Create an XML tree in a namespace.
XNamespace aw = "http://www.adventure-works.com";
XElement root = new XElement(aw + "Root", new XElement(aw + "Child", "child content"));
Console.WriteLine(root);
결과)
<Root xmlns="http://www.adventure-works.com">
  <Child>child content</Child>
</Root>

예2) 네임스페이스 접두사가 포함된 네임스페이스를 선언
// Create an XML tree in a namespace, with a specified prefix
XNamespace aw = "http://www.adventure-works.com";
XElement root = new XElement(aw + "Root",
    new XAttribute(XNamespace.Xmlns + "aw", "http://www.adventure-works.com"),
    new XElement(aw + "Child", "child content")
);
Console.WriteLine(root);
결과)
<aw:Root xmlns:aw="http://www.adventure-works.com">
  <aw:Child>child content</aw:Child>
</aw:Root>

예3)두 네임스페이스가 포함된 문서를 만드는 방법
두 네임스페이스 중 하나는 기본 네임스페이스이고 다른 하나는 접두사가 포함된 네임스페이스
루트 요소에 네임스페이스 특성을 포함하면 http://www.adventure-works.com이 기본 네임스페이스가 되도록 네임스페이스가 serialize되고
www.fourthcoffee.com이 "fc" 접두사를 사용하여 serialize됩니다.
기본 네임스페이스를 선언하는 특성을 만들려면 네임스페이스 없이 이름이 "xmlns"인 특성을 만듭니다.
특성 값은 기본 네임스페이스 URI입니다.
// The http://www.adventure-works.com namespace is forced to be the default namespace.
XNamespace aw = "http://www.adventure-works.com";
XNamespace fc = "www.fourthcoffee.com";
XElement root = new XElement(aw + "Root",
    new XAttribute("xmlns", http://www.adventure-works.com), //기본 네임스페이스가 된다.
    new XAttribute(XNamespace.Xmlns + "fc", "www.fourthcoffee.com"),
    new XElement(fc + "Child",
        new XElement(aw + "DifferentChild", "other content")
    ),
    new XElement(aw + "Child2", "c2 content"),
    new XElement(fc + "Child3", "c3 content")
);
Console.WriteLine(root);
결과)
<Root xmlns="http://www.adventure-works.com" xmlns:fc="www.fourthcoffee.com">
  <fc:Child>
    <DifferentChild>other content</DifferentChild>
  </fc:Child>
  <Child2>c2 content</Child2>
  <fc:Child3>c3 content</fc:Child3>
</Root>

예4)네임스페이스 접두사가 있는 두 가지 네임스페이스가 포함된 문서를 만들기
XNamespace aw = "http://www.adventure-works.com";
XNamespace fc = "www.fourthcoffee.com";
XElement root = new XElement(aw + "Root",
    new XAttribute(XNamespace.Xmlns + "aw", aw.NamespaceName),
    new XAttribute(XNamespace.Xmlns + "fc", fc.NamespaceName),
    new XElement(fc + "Child",
        new XElement(aw + "DifferentChild", "other content")
    ),
    new XElement(aw + "Child2", "c2 content"),
    new XElement(fc + "Child3", "c3 content")
);
Console.WriteLine(root);
결과)
<aw:Root xmlns:aw="http://www.adventure-works.com" xmlns:fc="www.fourthcoffee.com">
  <fc:Child>
    <aw:DifferentChild>other content</aw:DifferentChild>
  </fc:Child>
  <aw:Child2>c2 content</aw:Child2>
  <fc:Child3>c3 content</fc:Child3>
</aw:Root>

예5)확장된 이름이 포함된 문자열을 전달하여 위와 동일한 결과얻기
{}안의 내용을 파싱해야하므로 성능이 명시적으로 XNamespace를 선언하는 경우보다 떨어진다.
// Create an XML tree in a namespace, with a specified prefix
XElement root = new XElement("{http://www.adventure-works.com}Root",
    new XAttribute(XNamespace.Xmlns + "aw", "http://www.adventure-works.com"),
    new XElement("{http://www.adventure-works.com}Child", "child content")
);
Console.WriteLine(root);
결과)
<aw:Root xmlns:aw="http://www.adventure-works.com">
  <aw:Child>child content</aw:Child>
</aw:Root>

3.1.3.2. C#에서 기본 네임스페이스 범위(LINQ to XML)
XML 트리에 나타나는 기본 네임스페이스는 쿼리의 범위에 포함되지 않는다.
기본 네임스페이스에 있는 XML을 사용하는 경우 XNamespace 변수를 선언하고 로컬 이름과 결합하여
쿼리에서 사용할 정규화된 이름을 만들어야만 쿼리식에서 사용할 수 있다.

예1)집합에서는 기본 네임스페이스의 XML이 로드되지만 적절하지 않게 쿼리되는 경우의 예
XElement root = XElement.Parse(
@"<Root xmlns='http://www.adventure-works.com'>
    <Child>1</Child>
    <Child>2</Child>
    <Child>3</Child>
    <AnotherChild>4</AnotherChild>
    <AnotherChild>5</AnotherChild>
    <AnotherChild>6</AnotherChild>
</Root>");
IEnumerable<XElement> c1 =
    from el in root.Elements("Child")
    select el;
Console.WriteLine("Result set follows:");
foreach (XElement el in c1)
    Console.WriteLine((int)el);
Console.WriteLine("End of result set");
결과)
Result set follows:
End of result set

예2) 집합에서는 네임스페이스의 XML을 쿼리할 수 있도록 필요한 수정을 하는 방법을
XElement root = XElement.Parse(
@"<Root xmlns='http://www.adventure-works.com'>
    <Child>1</Child>
    <Child>2</Child>
    <Child>3</Child>
    <AnotherChild>4</AnotherChild>
    <AnotherChild>5</AnotherChild>
    <AnotherChild>6</AnotherChild>
</Root>");
XNamespace aw = "http://www.adventure-works.com";
IEnumerable<XElement> c1 =
    from el in root.Elements(aw + "Child") //명시적으로 지정.
    select el;
Console.WriteLine("Result set follows:");
foreach (XElement el in c1)
    Console.WriteLine((int)el);
Console.WriteLine("End of result set");
결과)
Result set follows:
1
2
3
End of result set

3.1.4 XML을 로드하기 위한 정적 메서드 지원 
예) 파일에서 XML 로드
XElement booksFromFile = XElement.Load(@"books.xml");
Console.WriteLine(booksFromFile);

3.1.5 DTD 구문에 대한 지원 제거  
LINQ to XML에서는 엔터티와 엔터티 참조에 대한 지원 기능을 제거하여 XML 프로그래밍을 더욱 단순화.  

3.1.6 조각에 대한 지원   
LINQ to XML에서는 XmlDocumentFragment 클래스와 동일한 항목을 제공하지만 대부분의 경우에 XmlDocumentFragment 개념은 XNode의 IEnumerable<(Of <(T>)>)이나 XElement의 IEnumerable<(Of <(T>)>)로 형식화된 쿼리의 결과에 의해 처리될 수 있다.

3.1.7 XPathNavigator에 대한 지원  
LINQ to XML에서는 System.Xml.XPath 네임스페이스의 확장 메서드를 통해 XPathNavigator를 지원.
System.Xml.XPath..::.Extensions 클래스의 멤버함수를 이용

3.1.7.1 Extensions..::.CreateNavigator 메서드
XNode에 대해 XPathNavigator를 만듬.
이 메서드에서 반환되는 XPathNavigator를 사용하여 XML 트리를 편집할 수 없다. (CanEdit 속성은 false로 반환).
XDocumentType 노드에 대해 XPathNavigator를 만들 수 없다.(문서형식(XDocumentType)은 XPath 데이터 모델과 관련이 없다)
네임스페이스 선언은 왼쪽에서 오른쪽으로 보고.
XmlDocument 네임스페이스는 오른쪽에서 왼쪽으로 보고.
이 메서드에서 반환되는 탐색기에 대해 MoveToId 메서드는 지원되지 않음.
이 메서드를 사용하여 XSLT 변환가능.

 예)XML 트리를 만들고, XML 트리에서 XPathNavigator를 만들고, 새 문서를 만들고, 새 문서에 쓸 XmlWriter를 만든다.
그런 다음 XPathNavigator 및 XmlWriter를 변환에 전달하여 XSLT 변환을 호출할 수 있다.
변환이 완료된 후 새 XML 트리는 변환 결과로 채운다.

XSLT 변환을 수행하려면 XmlReader 또는 XPathNavigator를 사용.
XmlReader를 사용할 때 더 빨리 실행되는 변환도 있고, XPathNavigator를 사용할 때 더 빨리 실행되는 변환도 있습니다.

string xslMarkup = @"<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
    <xsl:template match='/Parent'>
        <Root>
            <C1><xsl:value-of select='Child1'/></C1>
            <C2><xsl:value-of select='Child2'/></C2>
        </Root>
    </xsl:template>
</xsl:stylesheet>";

XDocument xmlTree = new XDocument(
    new XElement("Parent",
        new XElement("Child1", "Child1 data"),
        new XElement("Child2", "Child2 data")
    )
);

XDocument newTree = new XDocument();
using (XmlWriter writer = newTree.CreateWriter()) {
    // Load the style sheet.
    XslCompiledTransform xslt = new XslCompiledTransform();
    xslt.Load(XmlReader.Create(new StringReader(xslMarkup)));

    // Execute the transform and output the results to a writer.
    xslt.Transform(xmlTree.CreateNavigator(), writer);
}

Console.WriteLine(newTree);
결과)
<Root>
  <C1>Child1 data</C1>
  <C2>Child2 data</C2>
</Root>

3.1.7.2 Extensions..::.XPathEvaluate 메서드
XPath 식을 평가
예) 다음 예제에서는 특성이 있는 작은 XML 트리를 만든 다음 XPathEvaluate 메서드를 사용하여 특성을 검색합니다.
String xml = "<root a='value'/>";
XDocument d = XDocument.Parse(xml);
IEnumerable att = (IEnumerable)d.XPathEvaluate("/root/@a");
Console.WriteLine(att.Cast<XAttribute>().FirstOrDefault());
결과)
a="value"

3.1.7.3 Extensions..::.XPathSelectElement 메서드
XPath 식을 사용하여 XElement를 선택
예) 작은 XML 트리를 만든 다음 XPathSelectElement를 사용하여 단일 요소를 선택
XElement root = new XElement("Root",
    new XElement("Child1", 1),
    new XElement("Child2", 2),
    new XElement("Child3", 3),
    new XElement("Child4", 4),
    new XElement("Child5", 5),
    new XElement("Child6", 6)
);
XElement el = root.XPathSelectElement("./Child4");
Console.WriteLine(el);
결과)
<Child4>4</Child4>

3.1.7.4 Extensions..::.XPathSelectElements 메서드
XPath 식을 사용하여 요소 컬렉션을 선택
예) 작은 XML 트리를 만든 다음 XPathSelectElements를 사용하여 요소 집합을 선택합
XElement root = new XElement("Root",
    new XElement("Child1", 1),
    new XElement("Child1", 2),
    new XElement("Child1", 3),
    new XElement("Child2", 4),
    new XElement("Child2", 5),
    new XElement("Child2", 6)
);
IEnumerable<XElement> list = root.XPathSelectElements("./Child2");
foreach (XElement el in list)
    Console.WriteLine(el);
결과)
<Child2>4</Child2>
<Child2>5</Child2>
<Child2>6</Child2>

3.1.8 공백 및 들여쓰기에 대한 지원   
서식이 있는 XML을 serialize하는 경우 XML 트리의 유효 공백만 유지(LINQ to XML의 기본 동작)
LINQ to XML에서는 DOM의 경우처럼 serialize된 Whitespace 노드 형식을 사용하는 대신 XText 노드로 공백을 저장.

3.1.9 주석에 대한 지원    
LINQ to XML에서 주석을 사용하여 임의의 형식에 대한 임의의 개체를 XML 트리의 XML 구성 요소와 연결
주석은 XML infoset의 일부가 아니므로 serialize되거나 deserialize되지 않는다.
아래 메서드호출(형식별로 주석을 검색가능)
AddAnnotation - XObject의 주석 목록에 개체를 추가합니다.
Annotation - 지정된 형식의 첫 번째 주석 개체를 XObject에서 가져옵니다.
Annotations -  XObject에 대한 지정된 형식의 주석 컬렉션을 가져옵니다.
RemoveAnnotations - 지정된 형식의 주석을 XObject에서 제거합니다.

예1) XElement에 주석을 추가
 public class MyAnnotation {
    private string tag;
    public string Tag {get{return tag;} set{tag=value;}}
    public MyAnnotation(string tag) {
        this.tag = tag; }} public class Program {
    public static void Main(string[] args) {  
        MyAnnotation ma = new MyAnnotation("T1");
        XElement root = new XElement("Root", "content");
        root.AddAnnotation(ma);

        MyAnnotation ma2 = (MyAnnotation)root.Annotation<MyAnnotation>();
        Console.WriteLine(ma2.Tag);
    }
}
결과)
T1

예2)  요소의 주석을 검색.
public class MyAnnotation {
    private string tag;
    public string Tag {get{return tag;} set{tag=value;}}
    public MyAnnotation(string tag) {
        this.tag = tag; }} class Program {
    static void Main(string[] args) {  
        XElement root = new XElement("Root", "content");
        root.AddAnnotation(new MyAnnotation("T1"));
        root.AddAnnotation(new MyAnnotation("T2"));
        root.AddAnnotation("abc");
        root.AddAnnotation("def");

        IEnumerable<MyAnnotation> annotationList;
        annotationList = root.Annotations<MyAnnotation>();
        foreach (MyAnnotation ma in annotationList)
            Console.WriteLine(ma.Tag);
        Console.WriteLine("----");

        IEnumerable<string> stringAnnotationList;
        stringAnnotationList = root.Annotations<string>();
        foreach (string str in stringAnnotationList)
            Console.WriteLine(str);
    }
}
결과)
T1
T2
----
abc
def

3.1.10 스키마 정보에 대한 지원
LINQ to XML에서는 System.Xml.Schema 네임스페이스의 확장 메서드를 통해 XSD 유효성 검사를 지원
XML 트리가 XSD를 준수하는지 확인할 수 있으며, PSVI(Post-Schema-Validation Infoset)를 사용하여 XML 트리를 채울 수 있다
예1) XmlSchemaSet을 만든 다음 스키마 집합에 대해 두 XDocument 개체의 유효성을 검사.
string xsdMarkup =
    @"<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
       <xsd:element name='Root'>
        <xsd:complexType>
         <xsd:sequence>
          <xsd:element name='Child1' minOccurs='1' maxOccurs='1'/>
          <xsd:element name='Child2' minOccurs='1' maxOccurs='1'/>
         </xsd:sequence>
        </xsd:complexType>
       </xsd:element>
      </xsd:schema>";
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", XmlReader.Create(new StringReader(xsdMarkup)));

XDocument doc1 = new XDocument(
    new XElement("Root",
        new XElement("Child1", "content1"),
        new XElement("Child2", "content1")
    )
);

XDocument doc2 = new XDocument(
    new XElement("Root",
        new XElement("Child1", "content1"),
        new XElement("Child3", "content1")
    )
);

Console.WriteLine("Validating doc1");
bool errors = false;
doc1.Validate(schemas, (o, e) =>
                     {
                         Console.WriteLine("{0}", e.Message);
                         errors = true;
                     });
Console.WriteLine("doc1 {0}", errors ? "did not validate" : "validated");

Console.WriteLine();
Console.WriteLine("Validating doc2");
errors = false;
doc2.Validate(schemas, (o, e) =>
                     {
                         Console.WriteLine("{0}", e.Message);
                         errors = true;
                     });
Console.WriteLine("doc2 {0}", errors ? "did not validate" : "validated");
결과)
Validating doc1
doc1 validated

Validating doc2
The element 'Root' has invalid child element 'Child3'. List of possible elements expected: 'Child2'.
doc2 did not validate

예2) :Track('ctl00_rs1_mainContentContainer_cpe497038_c|ctl00_rs1_mainContentContainer_ctl23',this);" href="http://msdn.microsoft.com/ko-kr/library/bb387025.aspx">샘플 XML 파일: 고객 및 주문(LINQ to XML)에 있는 XML 문서가 :Track('ctl00_rs1_mainContentContainer_cpe497038_c|ctl00_rs1_mainContentContainer_ctl24',this);" href="http://msdn.microsoft.com/ko-kr/library/bb675181.aspx">샘플 XSD 파일: 고객 및 주문에 있는 스키마별로 유효한지 확인한 다음 소스 XML 문서를 수정합니다. 여기에서는 첫 번째 고객에 대한 CustomerID 특성을 변경합니다. 변경한 후에는 주문이 존재하지 않는 고객을 참조하게 되므로 XML 문서가 더 이상 유효하지 않습니다.
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", "CustomersOrders.xsd");

Console.WriteLine("Attempting to validate");
XDocument custOrdDoc = XDocument.Load("CustomersOrders.xml");
bool errors = false;
custOrdDoc.Validate(schemas, (o, e) =>
                     {
                         Console.WriteLine("{0}", e.Message);
                         errors = true;
                     });
Console.WriteLine("custOrdDoc {0}", errors ? "did not validate" : "validated");

Console.WriteLine();
// Modify the source document so that it will not validate.
custOrdDoc.Root.Element("Orders").Element("Order").Element("CustomerID").Value = "AAAAA";
Console.WriteLine("Attempting to validate after modification");
errors = false;
custOrdDoc.Validate(schemas, (o, e) =>
                     {
                         Console.WriteLine("{0}", e.Message);
                         errors = true;
                     });
Console.WriteLine("custOrdDoc {0}", errors ? "did not validate" : "validated");
결과)
Attempting to validate
custOrdDoc validated

Attempting to validate after modification
The key sequence 'AAAAA' in Keyref fails to refer to some key.
custOrdDoc did not validate


3.2. LINQ to XML과 다른 XML 기술 비교
LINQ to XML, XmlReader, XSLT, MSXML 및 XmlLite와 같은 XML 기술을비교

3.2.1 LINQ to XML 와 XmlReader
XmlReader는 캐시하지 않으며 정방향으로만 작동하는 빠른 파서.
LINQ to XML은 XmlReader를 기반으로 구현되었으며 두 기술은 밀접하게 통합되어 있다.( XmlReader를 단독으로 사용가능)

예)초당 수백 개의 XML 문서를 구문 분석할 웹 서비스를 빌드하는데 문서의 구조가 동일하여
XML의 구문을 분석하는 코드의 구현을 하나만 작성하면 되는 경우 XmlReader를 단독으로 사용할 수 있습니다.
반면에 크기가 작은 다양한 XML 문서의 구문을 분석하는 시스템을 빌드하는데 각 문서의 구조가 서로 다르면
LINQ to XML에서 제공하는 성능 향상 기능을 사용할 수 있습니다.

3.2.2 LINQ to XML 와 XSLT
LINQ to XML과 XSLT는 모두 광범위한 XML 문서 변환 기능을 제공
XSLT는 규칙 기반의 선언적 방법.
고급 XSLT 프로그래머는 상태 비저장 방법을 강조하는 함수형 프로그래밍 스타일로 XSLT를 작성.
이 경우 부작용 없이 구현되는 순수 함수를 사용하여 변환을 작성할 수 있다.
이 규칙 기반 방법 또는 함수 방법은 대부분의 개발자에게 익숙하지 않으며 배우는 데 많은 시간과 노력이 필요.

XSLT는 고성능 응용 프로그램을 생성하는 생산성이 매우 높은 시스템.
예를 들어 규모가 큰 일부 웹 회사에서는 다양한 데이터 저장소에서 가져온 XML에서 HTML을 생성하는 방법으로 XSLT를 사용.
관리되는 XSLT 엔진은 XSLT를 CLR 코드로 컴파일하며 일부 시나리오에서 네이티브 XSLT 엔진보다 성능이 훨씬 좋다.
그러나 XSLT에서는 개발자가 C# 및 Visual Basic 지식을 활용할 수 없으며 복잡하고 다른 프로그래밍 언어로 코드를 작성해야 합니다.
C#(또는 Visual Basic) 및 XSLT와 같은 통합되지 않은 두 가지 개발 시스템을 사용하면 소프트웨어 시스템을 개발하고 유지 관리하기가 더 어렵습니다.

LINQ to XML 쿼리 식을 완전히 익히고 나면 강력한 LINQ to XML 변환 기술을 쉽게 사용할 수 있다.
기본적으로 다양한 소스에서 데이터를 가져와서 XElement 개체를 동적으로 생성하고 전체 데이터를 새 XML 트리로 어셈블하는 함수 생성을 사용하여 XML 문서를 만든다.
변환을 통해 완전히 새로운 문서가 생성될 수 있다.
LINQ to XML에서는 비교적 쉽고 직관적으로 변환을 생성할 수 있으며 생성되는 코드도 쉽게 읽을 수 있다.
따라서 개발 및 유지 관리 비용이 줄어듭니다.

LINQ to XML은 XSLT를 대체하기 위한 것이 아니다.
XSLT는 여전히 복잡하고 문서 중심적인 XML(특히 문서 구조가 제대로 정의되지 않은 경우) 변환에 사용할 수 있다.

XSLT는 W3C(World Wide Web Consortium) 표준이므로 표준 기술만 사용해야 하는 요구 사항이 있는 경우 XSLT가 더 적합할 수 있다.
XSLT는 XML이므로 프로그래밍 방식으로 조작할 수 있다.

3.2.3 LINQ to XML과 MSXML 비교
MSXML은 Microsoft Windows에 포함된 XML을 처리할 수 있는 COM 기반 기술.
MSXML은 XPath 및 XSLT를 지원하는 DOM의 기본적인 구현을 제공하며 캐시하지 않는 이벤트 기반의 SAX2 파서도 포함하고 있다.
MSXML은 성능이 좋으며 대부분의 시나리오에서 기본적으로 안전.
AJAX 스타일의 응용 프로그램에서 클라이언트측 XML 처리를 수행하기 위해 Internet Explorer에서 MSXML에 액세스할 수 있다.
C++, JavaScript 및 Visual Basic 6.0을 비롯한 COM을 지원하는 모든 프로그래밍 언어에서 MSXML을 사용할 수 있다.
CLR(공용 언어 런타임) 기반의 관리 코드에서는 MSXML을 사용하지 않는 것이 좋다.

3.2.4 LINQ to XML과 XmlLite 비교
XmlLite는 캐시하지 않으며 정방향으로만 작동하는 가져오기 파서.
개발자는 주로 C++와 함께 XmlLite를 사용.
관리 코드와 함께 XmlLite를 사용하는 것은 권장되지 않는다.
XmlLite의 주요 이점은 대부분의 시나리오에서 안전하며 간단하고 빠른 XML 파서다.
 XmlLite에서 위협에 노출되는 영역은 매우 작다.
신뢰할 수 없는 문서의 구문을 분석해야 하고 서비스 거부나 데이터 노출과 같은 공격으로부터 보호하려면 XmlLite를 선택하는 것이 좋다.
XmlLite는 LINQ(통합 언어 쿼리)와 통합되지 않았으며 LINQ에 핵심적인 프로그래머 생산성 향상 기능을 제공하지 않는다.


출처: http://www.microsoft.com/korea/msdn/lib ··· wpf.aspx

Windows Presentation Foundation 설명

기본적으로 기술은 주로 전문가들이 중요하게 생각하는 부분으로 대부분의 소프트웨어 전문가들은 응용 프로그램과 사용자 간의 상호 작용 방식보다는 응용 프로그램의 작동 방식에 훨씬 더 많은 관심을 가집니다. 그러나 응용 프로그램을 구입하는 실제 사용자에게는 사용자 인터페이스가 매우 중요합니다. 응용 프로그램의 인터페이스는 해당 소프트웨어에 대한 전체적인 사용자 환경에서 중요한 부분을 차지하며, 사용자에게 이러한 환경은 응용 프로그램 '그 자체'를 의미합니다. 더 나은 인터페이스를 통해 향상된 사용자 환경을 제공하면 생산성을 높이고 우수 고객을 더 많이 확보할 수 있으며 웹 사이트에서의 매출을 늘리는 등 다양한 효과를 얻을 수 있습니다.

이전에는 문자 기반 인터페이스만으로 충분했지만 오늘날의 사용자들은 그래픽 인터페이스에 익숙해졌으며 사용자 인터페이스에 대한 요구 사항은 계속해서 증가하고 있습니다. 그래픽과 미디어가 더욱 광범위하게 사용되고 있으며 웹의 발전은 소프트웨어와의 편리한 상호 작용을 기대하는 사용자 계층을 형성하게 되었습니다. 사용자들이 응용 프로그램을 사용하는 시간이 늘어날수록 해당 응용 프로그램의 인터페이스는 더욱 중요해집니다. 이렇듯 점점 높아지는 인터페이스 요구 사항에 부응하기 위해서는 사용자 인터페이스를 만드는 기술도 함께 발전해야 합니다.

WPF(Windows Presentation Foundation)의 목표는 Windows에 바로 이러한 고급 기능을 제공하는 것입니다. Microsoft .NET Framework 버전 3.0에 포함된 WPF를 사용하면 문서, 미디어, 2차원 및 3차원 그래픽, 애니메이션, 웹 특성 등을 포함하는 인터페이스를 만들 수 있습니다. WPF는 .NET Framework 3.0의 모든 구성 요소와 마찬가지로 Windows Vista, Windows XP 및 Windows Server 2003에서 사용할 수 있으며 Windows Vista와 함께 출시될 예정입니다. 이 백서에서는 WPF를 소개하고 WPF의 다양한 구성 요소에 대해 설명하며 이 기술을 통해 해결할 수 있는 문제점과 WPF가 제공하는 솔루션에 대해 살펴봅니다.

문제점 예시

병원에서 환자를 진료하고 모니터링하는 데 사용할 새 응용 프로그램을 만든다고 가정해 보겠습니다. 새로 만들 응용 프로그램에는 다음과 같은 사용자 인터페이스가 필요할 수 있습니다.

  • 환자에 대한 이미지와 텍스트 표시
  • 심장 박동수, 혈압 등 환자의 활력 징후를 보여 주는 2차원 그래픽 표시 및 업데이트
  • 환자 정보에 대한 3차원 보기 및 오버레이 제공
  • 초음파 또는 기타 진단 비디오를 표시하고, 가능한 경우 의사나 간호사가 메모를 추가할 수 있는 기능 제공
  • 병원 직원이 환자 및 환자 상태에 대한 기록을 읽고 메모를 추가할 수 있는 기능
  • 병원 직원이 모든 기능을 사용할 수 있도록 Windows 응용 프로그램으로 실행되고 다른 위치에 있는 의사가 인터넷을 통해 제한적인 방식으로 액세스할 수 있도록 엄격한 보안이 유지되는 웹 브라우저 응용 프로그램으로도 실행

이러한 요구 사항은 야심적이기는 하지만 충분히 실현 가능합니다. 필요한 정보를 적시에 적절한 방법으로 제공하는 사용자 인터페이스는 업무상 중요한 가치를 지닙니다. 앞에서 설명한 의료 응용 프로그램의 예에서는 적절한 사용자 인터페이스가 생명을 구할 수도 있습니다. 온라인 상점 또는 기타 고객 지향 응용 프로그램과 같은 일반적인 시나리오의 경우 강력한 사용자 환경을 제공하면 회사의 서비스를 경쟁사의 서비스와 차별화하여 매출 증진은 물론 회사의 브랜드 가치를 높일 수 있습니다. 중요한 점은 많은 수의 최신 응용 프로그램에서 그래픽, 미디어, 문서 및 기타 최신 사용자 환경의 요소를 통합하는 인터페이스를 제공함으로써 다양한 이점을 누릴 수 있다는 것입니다.

2006년 현재의 기술로 Windows에 이러한 유형의 인터페이스를 만들 수도 있지만 이러한 작업은 다음과 같은 주요 장애 요인으로 인해 실현하기 매우 어렵습니다.

  • 그래픽, 이미지 및 비디오로 작업하는 데 서로 다른 여러 기술이 사용됩니다. 이러한 다양한 기술을 활용하기 위해 유능한 개발자를 찾는 것은 이러한 개발자가 만드는 응용 프로그램을 유지 관리하는 것만큼 어렵고 비용도 많이 듭니다.
  • 이러한 모든 기능을 사용자에게 효과적으로 제공하는 인터페이스를 디자인하는 일은 도전적인 과제입니다. 소프트웨어 개발자의 기술만으로는 이러한 인터페이스를 디자인할 수 없기 때문에 전문 디자이너가 필요하지만 여기에서 설명한 모든 기능을 갖춘 인터페이스를 개발하기 위해 디자이너와 개발자가 공동으로 작업하는 데는 많은 제약이 따릅니다.
  • 모든 기능을 갖춘 인터페이스를 독립 실행형 Windows 응용 프로그램 버전과 브라우저에 호스팅되는 버전의 두 가지 형식으로 제공하려면 서로 다른 두 가지 분야의 기술을 사용하여 각 버전을 개별적으로 구현해야 합니다. Windows 데스크톱 응용 프로그램은 Windows Forms 및 기타 기본적인 Windows 기술을 사용하여 구현하고 브라우저에 호스팅되는 응용 프로그램은 HTML 및 JavaScript를 사용하여 구현할 수 있습니다. 이 경우 서로 다른 두 분야의 기술을 갖춘 두 개의 개발자 그룹이 필요합니다.

강력한 기능을 제공하는 최신 사용자 인터페이스를 만드는 작업을 복잡하게 생각할 필요는 전혀 없습니다. 공통적인 기반을 사용하면 이러한 모든 문제를 해결하고 개발자에게 단일화된 접근 방식을 제공하는 동시에 디자이너도 작업에서 중요한 역할을 담당하도록 할 수 있습니다. 이것이 바로 WPF의 목표이며, 자세한 내용은 다음 섹션에서 설명합니다.

문제점 해결: Windows Presentation Foundation의 기능

WPF가 제공하는 가장 중요한 세 가지 특징은 최신 사용자 인터페이스를 제공하기 위한 통합 플랫폼, 개발자와 디자이너가 공동으로 작업할 수 있는 환경, 그리고 Windows 사용자 인터페이스와 웹 브라우저 사용자 인터페이스를 개발하기 위한 공통의 기술입니다. 이 섹션에서는 이러한 세 가지 특징에 대해 설명합니다.

최신 사용자 인터페이스를 제공하기 위한 통합 플랫폼

WPF를 사용하지 않는 환경에서 위 설명과 같은 Windows 사용자 인터페이스를 만들기 위해서는 여러 가지 기술을 함께 사용해야 합니다. 다음 표에서는 필요한 기술을 간략하게 보여 줍니다.

Windows Forms PDF Windows Forms/
GDI+
Windows Media Player Direct3D WPF
그래픽 인터페이스(예: 폼 및 컨트롤) X X
화면에 표시되는 문서 X X
고정된 형식의 문서 X X
이미지 X X
비디오 및 오디오 X X
2차원 그래픽 X X
3차원 그래픽 X X

개발자가 폼, 컨트롤 및 기타 Windows 그래픽 사용자 인터페이스의 일반적인 요소를 만들려면 대개 .NET Framework의 일부인 Windows Forms를 사용해야 합니다. 인터페이스에서 문서를 표시해야 할 경우 Windows Forms에서 부분적으로 지원되는 화면 표시 문서를 사용할 수 있지만 고정된 형식의 문서를 사용해야 할 경우에는 Adobe의 PDF 형식이 적합합니다. 이미지와 2차원 그래픽을 표시하려는 경우 개발자는 Windows Forms를 통해 액세스할 수 있는 고유한 프로그래밍 모델인 GDI+를 사용할 수 있습니다. 또한 비디오와 오디오 기능은 Windows Media Player를 통해 제공하고 3차원 그래픽 기능은 Windows 표준인 Direct3D를 통해 제공할 수 있습니다.

이렇게 복잡한 작업은 단지 이론적인 설명을 위한 것일 뿐이며 이를 실제로 실행하는 것은 적절하지 않다는 데 누구나 동의할 것입니다. 그러나 통합된 단일 솔루션인 WPF에서는 이 모든 것이 가능합니다. WPF가 설치된 컴퓨터에서 응용 프로그램을 만드는 개발자는 WPF 하나만으로 위에서 언급한 모든 문제를 해결할 수 있습니다. 즉, 이제는 여러 가지 독립적인 기술을 사용하는 대신 하나의 일관된 기반을 사용하여 사용자 인터페이스를 만들 수 있습니다.

물론 WPF가 이 표에 나와 있는 모든 기술을 대체하지는 않습니다. Windows Forms 응용 프로그램은 여전히 유용하게 활용될 것이며, WPF 환경에서도 일부 새 응용 프로그램에는 Windows Forms를 사용해야 할 수 있습니다. WPF를 Windows Forms와 상호 운용할 수 있다는 점은 주목할 만한 가치가 있습니다. 이에 대한 자세한 내용은 이 문서의 뒷부분에서 설명합니다. Windows Media Player도 여전히 독자적인 가치를 제공할 것이며 PDF 문서도 계속해서 사용될 것입니다. Direct3D 또한 게임이나 몇 가지 다른 유형의 응용 프로그램에서는 중요한 기술입니다. 실제로 WPF에서도 Direct3D를 통해 모든 렌더링 작업을 수행합니다.

그러나 WPF라는 단일 기술을 통해 광범위한 기능을 제공하면 최신 사용자 인터페이스를 훨씬 쉽게 구현할 수 있다는 장점이 있습니다. 다음 화면에서는 이러한 통합된 접근 방식의 이점을 쉽게 이해할 수 있도록 앞에서 설명한 WPF 기반 버전의 의료 응용 프로그램을 보여 줍니다.

그림 1. WPF 인터페이스에서는 이미지, 텍스트, 2D 그래픽, 3D 그래픽 등을 결합할 수 있습니다.

이 화면에서는 텍스트와 이미지를 비롯하여 2차원 그래픽 및 3차원 그래픽을 함께 볼 수 있습니다. 이 모든 인터페이스는 개발자가 GDI+ 또는 Direct3D와 같은 특수 그래픽 기술을 사용하는 코드를 작성할 필요 없이 WPF를 사용하여 생성되었습니다. WPF를 사용하면 다음 그림에서 볼 수 있는 초음파 진단 결과처럼 비디오를 표시하고 메모를 입력하는 기능을 구현할 수도 있습니다.

그림 2. WPF 인터페이스에는 비디오뿐만 아니라 사용자가 입력할 수 있는 텍스트 메모를 모두 포함할 수 있습니다.

WPF를 사용하면 읽기 편리한 방식으로 문서를 표시할 수 있습니다. 예를 들어 병원 응용 프로그램의 경우 의사가 환자의 처방전에 대한 기록을 조회하거나 관련 항목에 대한 최근의 의학 연구 자료에 액세스할 수 있습니다. 아래의 화면에서 볼 수 있는 것처럼 의사는 메모를 추가할 수 있습니다.

그림 3. WPF 인터페이스에서는 메모를 포함하여 여러 개의 열이 있는 문서를 표시할 수 있습니다.

이 화면에서 문서는 가독성이 뛰어난 열 형식으로 표시되고 사용자는 스크롤 방식이 아니라 문서를 한 페이지씩 이동할 수 있습니다. 화면을 보기 쉽게 표시하는 것도 WPF의 중요한 목표 중 하나입니다. 그러나 화면에 표시되는 문서보다 고정된 형식의 문서를 사용하는 것이 적절한 경우도 있습니다. 고정된 형식의 문서는 화면에서 볼 때나 인쇄했을 때 모양이 동일하기 때문에 항상 일관된 모양을 제공합니다. 이러한 형식의 문서를 정의하기 위해 Microsoft는 XPS(XML Paper Specification)를 만들었습니다. WPF는 개발자가 XPS 문서를 만들고 작업하는 데 사용할 수 있는 API(응용 프로그래밍 인터페이스) 그룹도 제공합니다.

그러나 최신 사용자 인터페이스를 만드는 것은 독립적인 여러 기술을 단순히 통합하는 것이 아니라 최신 그래픽 카드의 장점을 활용할 수 있다는 의미를 가지고 있습니다. 즉, WPF는 시스템의 GPU(Graphics Processing Unit)에 가능한 한 많은 작업 로드를 분산시킴으로써 GPU를 최대한 활용합니다. 또한 최신 인터페이스는 비트맵 그래픽의 한계에 제약을 받지 않아야 하므로 WPF는 화면의 크기와 해상도에 맞게 이미지 크기가 자동으로 조정되도록 벡터 그래픽 기술을 사용합니다. 따라서 개발자는 작은 모니터와 대형 TV 화면에 표시할 그래픽을 개별적으로 만들지 않고 WPF를 통해 이러한 크기 조정 작업을 자동으로 처리할 수 있습니다.

WPF는 사용자 인터페이스를 만드는 데 필요한 모든 기술을 하나의 기반에 집약함으로써 이러한 인터페이스를 만드는 개발자의 업무 부담을 크게 낮추어 줍니다. WPF를 사용하는 경우 개발자는 하나의 작업 환경만 파악하면 되기 때문에 응용 프로그램 개발 및 유지 관리에 소요되는 비용이 훨씬 저렴합니다. 또한 WPF를 사용하면 그래픽, 비디오 등의 다양한 요소가 포함된 인터페이스를 간단하게 구현할 수 있으므로 사용자가 Windows 응용 프로그램과 상호 작용하는 방식을 개선하고 업무 효율성을 높일 수 있습니다.

개발자와 디자이너가 공동으로 작업할 수 있는 환경

모든 기능을 갖춘 사용자 인터페이스를 만들기 위한 통합된 기술 기반을 제공하는 것은 매우 바람직합니다. 그러나 개발자가 외부의 도움 없이 이러한 강력한 기능을 제대로 활용하여 이해하기 쉽고 사용이 편리한 인터페이스를 만들 수 있을 것이라고 기대하는 것은 무리입니다. 특히 앞에서 설명한 병원 사례와 같이 포괄적이고 유용한 사용자 인터페이스를 만들기 위해서는 대부분의 소프트웨어 전문가들이 갖추지 못한 인터페이스 디자인 기술이 필요합니다. 소프트웨어 전문가들이 많은 수의 응용 프로그램을 단독으로 개발하고 있지만 최상의 사용자 인터페이스를 구현하기 위해서는 전문 인터페이스 디자이너의 도움이 필요합니다.

그러나 개발자와 디자이너는 업무 진행 방식이 서로 다르기 때문에 두 분야의 전문가가 공동으로 작업하는 데는 여러 가지 문제가 있습니다. 일반적으로 디자이너는 그래픽 도구를 사용하여 응용 프로그램에 표시할 화면 레이아웃의 정적 이미지를 만듭니다. 그런 다음 이러한 이미지를 개발자에게 전달하고, 개발자는 해당 이미지를 구현하는 코드를 작성합니다. 그러나 디자이너는 만들기 쉽더라도 개발자는 구현하기 어렵거나 전혀 구현할 수 없는 이미지도 있습니다. 예를 들어 개발자는 기술적인 한계, 촉박한 일정, 기술 부족, 사소한 오해 또는 단순한 의견 차이로 인해 디자이너의 의도를 완벽하게 구현하지 못할 수 있습니다. 따라서 최상의 인터페이스를 만들기 위해서는 독립적인 두 분야의 전문가가 인터페이스의 품질을 떨어뜨리지 않으면서 공동으로 작업할 수 있는 환경이 필요합니다.

WPF는 이러한 공동 작업이 가능하도록 XAML(eXtensible Application Markup Language)을 사용합니다. XAML은 사용자 인터페이스의 모양을 정확하게 정의하기 위해 Button, TextBox, Label 등 여러 XML 요소의 집합을 정의합니다. 일반적으로 XAML 요소는 다양한 옵션을 설정할 수 있도록 특성도 포함합니다. 예를 들어 다음의 간단한 XAML 코드는 "아니요"라는 단어가 표시되는 빨간색 단추를 만듭니다.

<Button Background="Red">
 아니요
</Button>

각 XAML 요소는 WPF 클래스에 해당하고 요소의 각 특성은 클래스의 해당 속성이나 이벤트를 갖습니다. 예를 들어 다음과 같은 C# 코드를 사용하여 동일한 빨간색 단추를 만들 수 있습니다.

Button btn = new Button();
btn.Background = Brushes.Red;
btn.Content = "아니요";

XAML로 표현할 수 있는 모든 것을 코드를 사용하여 동일하게 작성할 수 있다면 XAML을 사용할 필요가 없다고 생각할 수도 있습니다. 그러나 XML 기반의 설명을 생성하고 사용하는 작성 도구를 사용하면 코드를 사용하여 동일한 작업을 할 때보다 훨씬 쉽게 작업할 수 있습니다. XAML은 사용이 편리한 도구 방식으로 사용자 인터페이스를 설명하기 때문에 개발자와 디자이너가 더 효율적으로 함께 작업할 수 있습니다. 다음 그림은 이러한 작업 과정을 보여 줍니다.

그림 4. 디자이너와 개발자의 공동 작업을 돕는 XAML

디자이너는 Microsoft Expression Interactive Designer와 같은 도구를 사용하여 사용자 인터페이스의 모양과 상호 작용 방식을 지정할 수 있습니다. 이 도구는 WPF 인터페이스의 모양과 느낌을 정의하는 용도로 사용되며 해당 인터페이스에 대한 설명을 XAML 표현으로 생성합니다. 예제로 사용된 간단한 단추만 포함하더라도 이 설명은 실제로 위에 나온 코드 조각보다 훨씬 복잡합니다. 개발자는 이 XAML 설명을 Microsoft Visual Studio와 같은 도구로 가져옵니다. 이렇게 하면 디자이너가 만든 정적 이미지를 토대로 인터페이스를 처음부터 다시 만들 필요 없이 인터페이스 정의 자체를 그대로 가져올 수 있습니다. 그런 다음 개발자는 이벤트 처리기와 같이 인터페이스에 필요한 코드 및 응용 프로그램에 필요한 기타 기능에 해당하는 코드를 작성합니다. 또한 응용 프로그램 인터페이스에 전체적으로 적용할 수 있는 스타일을 만들 수도 있으며, 이러한 스타일은 나중에 필요에 따라 사용자 지정할 수 있습니다.

디자이너와 개발자가 이러한 방식으로 함께 작업하면 디자이너가 만든 이미지를 토대로 개발자가 인터페이스를 구현할 경우 발생할 수 있는 변환 오류를 줄일 수 있을 뿐만 아니라 이러한 두 분야의 전문가가 반복 작업을 신속하게 수행하고 효과적으로 의견을 교환하면서 동시에 작업을 진행할 수 있습니다. 또한 두 환경 모두에서 동일한 빌드 시스템을 사용하므로 두 개발 환경 간에 WPF 응용 프로그램을 주고 받을 수도 있습니다. 3차원 인터페이스 요소를 만들기 위한 Electric Rain의 ZAM 3D와 같이 XAML로 정의된 인터페이스를 디자인하는 데 사용할 수 있는 특수한 도구도 있습니다.

더 나은 인터페이스를 사용하면 생산성을 높일 수 있을 뿐만 아니라 여러 가지 측면에서 업무상 매우 유용합니다. 그러나 효과적인 인터페이스를 만드는 데는 특히 WPF가 제공하는 다양한 환경의 경우 디자이너의 역할이 가장 중요합니다. XAML 및 XAML을 지원하는 도구의 기본적인 목표는 디자이너의 작업을 돕는 것입니다.

Windows 사용자 인터페이스와 웹 브라우저 사용자 인터페이스를 개발하기 위한 공통의 기술

Windows 응용 프로그램에 사용할 효과적인 사용자 인터페이스를 만드는 것도 중요하지만 웹 기반 응용 프로그램에 사용할 효과적인 인터페이스를 만드는 것도 그만큼 중요합니다. 기본적으로 이러한 인터페이스는 웹 브라우저에서 제공합니다. 인터페이스를 만드는 가장 간단한 방법은 브라우저에 전달되는 모든 HTML을 브라우저가 수동적으로 표시하도록 하는 것입니다. 응답 성능이 더 뛰어난 브라우저 인터페이스에서는 대개 AJAX(Asynchronous JavaScript And XML)를 사용하여 JavaScript로 실행되는 논리를 제공합니다. Adobe Flash Player 또는 몇 가지 다른 기술을 사용하여 애니메이션, 비디오 등을 인터페이스에 사용할 수도 있습니다. 이와 같이 기능이 다양한 인터페이스 유형을 제공하는 웹 소프트웨어를 '다기능 인터넷 응용 프로그램'이라고도 합니다. 이 웹 소프트웨어를 사용하면 사용자 환경을 크게 향상시킬 수 있을 뿐만 아니라 더 많은 사용자의 참여를 유도하는 웹 응용 프로그램을 만들어 상당한 비즈니스 가치를 얻을 수 있습니다.

일반적으로 이러한 유형의 인터페이스를 구현하기 위해서는 기본적인 Windows 인터페이스에 사용되는 것과는 완전히 다른 기술을 사용해야 합니다. 결과적으로 개발자는 서로 다른 두 가지 작업, 즉 Windows 인터페이스를 개발하는 작업 또는 웹 인터페이스 개발하는 작업 중 하나에 초점을 두고 작업해야 합니다. 그러나 Windows에서 액세스할 다기능 인터넷 응용 프로그램을 만드는 데 이러한 양분된 방식으로 작업할 필요는 없으며 기본적인 Windows 인터페이스와 웹 브라우저 인터페이스 모두에 동일한 기술을 사용하지 못할 이유도 없습니다.

WPF를 사용하면 동일한 기술을 사용하여 Windows 인터페이스와 웹 브라우저 인터페이스 모두를 만드는 것이 가능합니다. 개발자는 WPF를 사용하여 Internet Explorer에서 실행되는 XBAP(XAML Browser Application)를 만들 수 있습니다. 실제로 동일한 코드를 사용하여 독립 실행형 WPF 응용 프로그램과 XBAP를 만들 수 있습니다. 예를 들어 아래의 화면에서는 독립 실행형 Windows 응용 프로그램으로 실행되는 재무 서비스 응용 프로그램을 보여 줍니다. 앞에서 설명한 병원 응용 프로그램과 마찬가지로 이 응용 프로그램도 텍스트, 이미지 및 다양한 종류의 그래픽을 함께 사용합니다. 이 화면에서는 시계 등의 가젯 및 응용 프로그램 창 주위에 반투명 테두리를 사용하는 Aero 테마가 적용된 Windows Vista 바탕 화면도 볼 수 있습니다.

그림 5. 재무 서비스 응용 프로그램을 독립 실행형 WPF 응용 프로그램으로 실행할 수 있습니다.

다음 그림에서는 이 인터페이스를 Internet Explorer에서 XBAP로 실행할 때의 모양을 보여 줍니다.

그림 6. 동일한 응용 프로그램을 XBAP로도 실행할 수 있습니다.

이 경우 인터페이스가 자체 창에서 실행되는 대신 브라우저에서 실행된다는 점만 다를 뿐 모든 기능은 동일합니다. 두 경우 모두에 동일한 코드를 사용하면 두 가지 유형의 인터페이스를 개별적으로 만드는 데 소요되는 것보다 작업량을 줄일 수 있습니다. 동일한 코드를 사용한다는 것은 동일한 개발자를 투입할 수 있음을 의미합니다. WPF를 사용하면 개발자를 Windows 인터페이스 개발자 또는 웹 인터페이스 개발자라는 분리된 두 개의 그룹으로 구분할 필요 없이 하나의 개발 리소스를 두 작업 모두에 활용할 수 있습니다.

동일한 기술을 사용하여 Windows 인터페이스와 웹 인터페이스를 만들면 응용 프로그램 작성자가 응용 프로그램의 인터페이스 유형을 미리 결정하지 않아도 된다는 또 하나의 장점이 있습니다. 즉, 대상 클라이언트가 XBAP를 실행하는 데 필요한 요구 사항을 충족하기만 하면 응용 프로그램에서는 거의 동일한 코드를 사용하여 Windows 인터페이스나 웹 인터페이스 또는 두 가지 인터페이스 모두를 제공할 수 있습니다.

XBAP는 필요할 때 웹 서버에서 다운로드되기 때문에 독립 실행형 Windows 응용 프로그램에 비해 더욱 엄격한 보안 요구 사항이 적용됩니다. 이러한 이유로 XBAP는 .NET Framework의 코드 액세스 보안에서 제공하는 보안 샌드박스(Security Sandbox)에서 실행됩니다. 또한 XBAP는 WPF가 설치되어 있는 Windows 시스템에서 Internet Explorer 버전 6 및 7에서만 실행됩니다. 이러한 요구 사항이 충족되면 인터넷 응용 프로그램이 독립 실행형 Windows 응용 프로그램과 동일한 기반을 활용하는 것이 가능합니다.

Windows Presentation Foundation 사용

WPF로 해결할 수 있는 문제점만 알고 있어도 도움이 되지만 WPF가 이러한 문제점을 해결하는 방법을 이해한다면 더 큰 도움이 됩니다. 이 섹션에서는 WPF 기술 자체를 자세하게 살펴본 후 Windows 데스크톱 응용 프로그램, XBAP 및 XPS 문서에 WPF 기술이 적용되는 다양한 방식에 대해 알아봅니다.

Windows Presentation Foundation의 기술

WPF는 사용자 인터페이스를 만들기 위한 통합된 기반을 제공하지만 WPF에 포함된 기술을 문서, 이미지, 그래픽, 애니메이션 등과 같은 개별 단위로 나누어 살펴볼 수 있습니다. 이러한 모든 개별 단위는 다음에 설명할 WPF의 기본 응용 프로그램 모델에 의존합니다.

응용 프로그램 모델

.NET Framework의 다른 구성 요소와 마찬가지로 WPF의 기능은 System.Windows 네임스페이스에 포함된 네임스페이스 그룹으로 나뉩니다. 모든 WPF 응용 프로그램의 기본 구조는 어느 기능을 사용하는지에 관계없이 거의 동일합니다. 일반적으로 응용 프로그램은 독립 실행형 Windows 응용 프로그램이나 XBAP에 관계없이 XAML 페이지 집합과 이들 페이지에 연결된 코드로 구성됩니다.

기본적으로 모든 응용 프로그램은 WPF의 표준 Application 클래스에서 상속됩니다. 이 클래스는 모든 응용 프로그램에서 유용하게 사용할 수 있는 공통 서비스를 제공하며, 여기에는 전체 응용 프로그램에 필요한 상태를 유지하는 서비스 및 응용 프로그램을 시작하는 Run, 응용 프로그램을 종료하는 Shutdown 등의 표준 메서드를 제공하는 서비스가 포함됩니다.

Application 개체는 Application 요소를 통해 XAML을 사용하여 만들거나 Application 클래스를 통해 코드를 사용하여 만들 수 있습니다. 이러한 특징은 사실상 WPF의 모든 요소에 적용되지만 이 문서에서는 간단히 설명하기 위해 XAML을 사용하는 방식만을 소개할 것입니다. 다음은 간단한 XAML을 보여 줍니다.

<Application xmlns=   
    "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     StartupUri="Page1.xaml"
     x:Class="Example.SimpleApp">
. . . 
</Application>

이 정의에서는 먼저 WPF 네임스페이스를 이 요소의 기본값으로 지정한 다음 XAML 네임스페이스의 접두사를 정의합니다. XAML은 WPF에만 사용되는 것이 아니므로 이 두 네임스페이스는 서로 다릅니다. 다음으로 StartupUri 특성을 사용하여 응용 프로그램을 시작했을 때 로드하고 표시할 XAML 페이지의 이름을 나타냅니다. 마지막 특성인 Class는 이 Application과 관련된 코드가 들어 있는 클래스를 식별하는 데 사용됩니다. 앞에서 살펴본 것처럼 일반적으로 WPF 응용 프로그램에는 C# 또는 Visual Basic으로 작성된 코드와 XAML이 모두 들어 있으므로 이 클래스의 코드는 '코드 숨김' 파일에 저장됩니다. 여는 Application 태그 다음에는 이 응용 프로그램을 정의하는 데 필요한 나머지 XAML이 위치하고(여기에서는 생략됨), 마지막으로 Application 요소의 닫는 태그가 위치합니다.

모든 WPF 응용 프로그램은 동일한 루트 클래스에서 파생되지만 개발자는 다양한 옵션을 선택할 수 있습니다. 그 중 가장 중요한 옵션은 응용 프로그램에 일반적인 대화 상자 형식의 인터페이스를 사용할지 아니면 탐색 형식의 인터페이스를 사용할지 결정하는 것입니다. 대화 상자 형식의 인터페이스는 Windows 사용자라면 누구나 익숙한 단추 및 기타 요소를 제공합니다. 반면 탐색 형식의 인터페이스는 브라우저와 동작 방식이 거의 유사합니다. 예를 들어 탐색 형식의 인터페이스를 사용하면 대화 상자가 새 창에서 열리는 대신 새 페이지가 로드됩니다. 이와 같은 인터페이스는 페이지 그룹으로 구현되며, 각 페이지는 XAML에 정의된 사용자 인터페이스와 프로그래밍 언어로 표현된 논리로 구성됩니다. HTML로 정의된 브라우저 페이지와 마찬가지로 XAML은 페이지를 서로 연결하는 데 사용할 수 있는 Hyperlink 요소를 제공합니다. 사용자는 웹 기반 응용 프로그램의 페이지를 탐색할 때와 같은 방법으로 기록 목록을 통해 앞으로 또는 뒤로 이동하면서 여러 페이지를 탐색할 수 있습니다. 그러나 이것은 Windows 응용 프로그램이므로 혼동하지 말아야 합니다. 일반적으로 XBAP에서 이러한 유형의 인터페이스를 사용하지만, 필요에 따라 독립 실행형 Windows 응용 프로그램에서도 탐색 형식의 인터페이스를 통해 사용자와 상호 작용할 수 있습니다. 어떤 방식을 사용할지는 응용 프로그램을 만드는 개발자의 선택에 달려 있습니다.

응용 프로그램에서 어떤 인터페이스 스타일을 사용하든지 여부에 관계없이 응용 프로그램은 일반적으로 하나 이상의 창을 표시합니다. WPF는 창을 표시하기 위한 몇 가지 옵션을 제공합니다. 기본 Window 클래스에서는 창을 표시하고 숨기고 닫는 등의 기본적인 창 기능을 제공합니다. 일반적으로 탐색 형식의 인터페이스를 사용하지 않는 WPF 응용 프로그램에서 이 클래스를 사용합니다. NavigationWindow 클래스는 탐색 형식의 인터페이스를 사용하는 응용 프로그램에서 사용하며 기본 Window 클래스에 탐색 기능이 추가됩니다. 추가적인 탐색 기능으로는 응용 프로그램에서 새 페이지로 이동하는 데 사용할 수 있는 Navigate 메서드, 사용자의 탐색 기록을 저장하는 추적 정보 및 다양한 탐색 관련 이벤트가 있습니다.

레이아웃 및 컨트롤

WPF 응용 프로그램에서는 인터페이스의 다양한 요소를 구성하기 위해 '패널'을 사용하여 레이아웃을 지정합니다. 각 패널에는 단추, 텍스트 상자 등의 '컨트롤' 및 다른 패널이 자식 요소로 포함될 수 있습니다. 패널 종류마다 서로 다른 레이아웃 옵션을 제공합니다. 예를 들어, 이름에서 알 수 있듯이 DockPanel을 사용하면 자식 요소를 패널 가장자리에 도킹하여 배치할 수 있고, Grid를 사용하면 자식 요소를 눈금 위에 정확하게 배치할 수 있습니다. 이때 개발자는 눈금의 행 및 열 개수를 정의한 다음 자식 요소를 배치할 정확한 위치를 지정해야 합니다. Canvas를 사용하면 패널 경계 내의 아무 곳에나 자식 요소를 자유롭게 배치할 수 있습니다.

WPF는 다른 사용자 인터페이스 기술과 마찬가지로 다양한 컨트롤 집합을 제공합니다. 개발자는 사용자 지정 컨트롤을 만들 수도 있습니다. 표준 컨트롤 집합에는 Button, Label, TextBox, ListBox, Menu, Slider 및 기타 일반적인 사용자 인터페이스 디자인 요소가 포함됩니다. 또한 SpellCheck, PasswordBox, 잉크(예: Tablet PC)로 작업하는 데 필요한 컨트롤 등 보다 복잡한 컨트롤도 사용할 수 있습니다.

WPF 응용 프로그램에서는 일반적인 그래픽 인터페이스와 마찬가지로 마우스 이동 및 키 누르기 동작과 같이 사용자가 생성하는 이벤트를 컨트롤을 통해 포착하고 처리할 수 있습니다. 컨트롤 및 기타 사용자 인터페이스 요소는 XAML을 사용하여 완벽하게 지정할 수 있지만 이벤트는 코드에서 처리해야 합니다. 예를 들어 다음 XAML에서는 Canvas에 간단한 Button을 정의합니다.

<Canvas xmlns=
   "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="Example.CodeForCanvas">
  <Button Click="Button_Click">
   여기를 클릭하십시오.
  </Button>
</Canvas>

여는 Canvas 태그는 일반적인 WPF 및 XAML 네임스페이스 정의로 시작됩니다. 다음으로 이 XAML과 관련된 코드를 .NET Framework 네임스페이스 Example에 들어 있는 CodeForCanvas 클래스에서 찾을 수 있음이 지정되고, 그 다음에 "여기를 클릭하십시오."라는 화면 표시 텍스트를 지정하는 Button이 정의됩니다. 여는 Button 태그의 Click 특성은 이 단추의 click 이벤트가 Button_Click이라는 메서드를 사용하여 처리됨을 나타냅니다. 다음은 이 메서드의 코드입니다.

namespace Example {
  public partial class CodeForCanvas : Canvas  {
    void Button_Click(object sender, RoutedEventArgs e)    {
      Button btn = e.Source as Button;
      btn.Background = Brushes.Purple; 
    }
  }
}

네임스페이스 및 클래스의 이름은 위의 Canvas 태그에 지정된 것과 일치합니다. CodeForCanvas 클래스는 WPF에서 제공하는 기본 Canvas 클래스에서 상속되며 partial 클래스로 정의됩니다. Partial 클래스는 .NET Framework 버전 2.0에 새로 추가된 요소로서 개별적으로 정의된 코드를 단일 클래스로 결합하는 데 사용됩니다. 이 경우 XAML로 정의한 Canvas에서 생성되는 partial 클래스와 이 코드의 partial 클래스가 결합됩니다. 그 결과 단추가 포함된 캔버스를 표시하고 해당 단추의 이벤트도 처리할 수 있는 완전한 클래스가 생성됩니다.

이벤트를 처리하는 Button_Click 메서드는 CodeForCanvas 클래스 안에 선언됩니다. 이 메서드는 일반적인 .NET Framework 규칙에 따라 이벤트를 처리하지만 이벤트의 인수는 WPF로 정의된 RoutedEventArgs 클래스를 사용하여 전달됩니다. 이 클래스의 Source 속성은 이벤트를 생성한 Button에 대한 참조를 포함하며 메서드는 이 정보를 사용하여 단추의 색을 보라색으로 변경합니다.

이러한 간단한 예제에서 볼 수 있는 것처럼 WPF 사용자 인터페이스의 요소는 시각적 트리 형식으로 구성됩니다. 이 예제에서는 트리가 Canvas와 유일한 자식 요소인 Button으로 구성되지만 실제 WPF 응용 프로그램에서는 일반적으로 트리가 훨씬 더 복잡해집니다. 화면 표시 인터페이스를 실제로 만들려면 이 시각적 트리를 렌더링해야 합니다. WPF는 가능한 한 하드웨어 렌더링을 사용함으로써 응용 프로그램의 컴퓨터에 설치되어 있는 그래픽 카드를 통해 작업을 처리합니다. 그러나 컴퓨터의 그래픽 하드웨어로 작업을 처리할 수 없는 경우 WPF는 자체 소프트웨어를 사용하여 인터페이스를 렌더링합니다. 이러한 결정은 런타임에 WPF에서 내리기 때문에 개발자는 별도의 작업을 할 필요가 없습니다.

렌더링을 하드웨어 또는 소프트웨어에서 처리하는지 여부에 관계없이 WPF는 항상 유지 모드 그래픽이라는 방식을 사용합니다. 응용 프로그램 작성자가 일반적으로 XAML과 코드를 조합하여 시각적 트리의 모양을 정의하면 WPF 자체에 이 트리의 정보가 유지됩니다. 예를 들어 사용자가 창을 표시할 경우 응용 프로그램에서 창 전체 또는 일부를 다시 그릴 필요 없이 WPF에서 이 작업을 자체적으로 처리합니다. 트리를 구성하는 요소는 화면에 픽셀로 저장되지 않고 개체로 저장되기 때문에 WPF는 이러한 유형의 렌더링을 처리하는 데 충분한 정보를 항상 유지합니다. 창과 창에 포함된 컨트롤의 크기를 조정하는 경우에도 WPF는 자체적으로 모든 렌더링을 다시 수행할 수 있습니다. WPF는 선, 타원 등의 그래픽 형태를 파악하고 비트맵이 아니라 벡터 그래픽을 사용하기 때문에 이와 같은 충분한 정보를 사용하여 새로운 크기로 인터페이스를 다시 만들 수 있습니다.

스타일 및 서식 파일

몇 가지 사용자 인터페이스 요소의 모양을 한 번 정의한 다음 그 모양을 여러 번 다시 적용하면 편리한 경우가 있습니다. 예를 들어 HTML 페이지에서는 CSS(Cascading Style Sheet)를 사용하여 이러한 작업을 수행할 수 있습니다. WPF에서는 '스타일'이 이와 유사한 기능을 합니다. 이미 널리 사용되고 있는 CSS 스타일시트의 경우에서 볼 수 있듯이 스타일을 정의하는 기능을 매우 유용하게 사용할 수 있습니다. 예를 들어 스타일을 사용하면 디자이너와 개발자의 작업 영역을 보다 명확하게 구분할 수 있기 때문에 디자이너가 인터페이스에 일관된 모양을 만들면 개발자는 이러한 세부 사항에 신경쓰지 않아도 됩니다.

WPF 응용 프로그램 작성자는 XAML의 Style 요소를 사용하여 특정 항목의 모양에 대한 특징을 하나 이상 정의한 후 해당 스타일을 반복적으로 적용할 수 있습니다. 예를 들어 ButtonStyle이라는 스타일을 다음과 같이 정의할 수 있습니다.

<Style x:Key="ButtonStyle">
  <Setter Property="Control.Background" Value="Red"/>
  <Setter Property="Control.FontSize" Value="16"/>
</Style>

이 스타일을 사용하여 정의하는 모든 단추에는 빨간색 배경이 사용되고 글꼴 크기가 16으로 지정됩니다. 예를 들면 다음과 같습니다.

  <Button Style="{StaticResource ButtonStyle}">
   여기를 클릭하십시오.
  </Button>

이 예제에 나와 있는 "StaticResource"의 형태에서 알 수 있듯이 일반적으로 WPF 스타일은 리소스로 정의됩니다. 리소스는 응용 프로그램 코드와는 별도로 정의되는 데이터입니다.

스타일은 이 예제에서 설명한 것보다 훨씬 다양한 기능을 제공합니다. 예를 들어 다른 스타일에서 스타일을 파생시킬 수 있습니다. 이 경우 원래의 설정을 상속하거나 필요에 따라 재정의할 수 있습니다. 스타일을 사용하면 대화형 동작의 일반적인 측면을 지정하는 '트리거'를 정의할 수도 있습니다. 예를 들어 마우스로 단추를 가리키면 단추 배경이 노란색으로 바뀌도록 스타일을 지정할 수 있습니다.

WPF는 '서식 파일' 기능도 지원합니다. 서식 파일은 스타일과 유사하며, 다음과 같은 두 가지 유형으로 나뉩니다.

  • 데이터 서식 파일: XAML의 DataTemplate 요소를 사용하여 데이터 표시 방법에 대한 특성 그룹을 지정할 수 있습니다. 데이터 서식 파일에 색, 정렬 방식 등의 특성을 정의한 후 응용 프로그램의 사용자 인터페이스에 자유롭게 사용할 수 있습니다.
  • 컨트롤 서식 파일: XAML의 ControlTemplate 요소를 사용하여 컨트롤의 모양을 정의할 수 있습니다.

응용 프로그램의 인터페이스 모양을 간단하게 정의할 수 있는 방법을 제공하면 응용 프로그램 작성자가 작업하는 데 큰 도움이 될 수 있습니다. WPF에서는 기본적으로 스타일과 서식 파일을 통해 인터페이스 모양을 보다 쉽게 정의할 수 있습니다.

텍스트

대부분의 사용자 인터페이스에는 적어도 어느 정도의 텍스트가 표시되고, 다른 특성은 거의 없이 텍스트만 표시되는 사용자 인터페이스도 있습니다. 그러나 대다수의 사용자들은 화면에서 텍스트를 읽는 것보다 인쇄된 페이지를 읽는 것을 더 선호합니다. 사람들은 책이나 잡지에서 일반적으로 볼 수 있는 고품질의 문자 모양과 글자에 익숙해져 있기 때문에 화면에 표시되는 텍스트를 읽을 때는 왠지 모르게 불편함을 느끼는 것이 사실입니다.

WPF는 인쇄된 페이지를 읽는 것처럼 화면 표시 텍스트도 편하게 읽을 수 있도록 이러한 차이를 줄이는 것을 목표로 합니다. 이러한 목표의 일환으로 WPF에서는 기존 글꼴 라이브러리를 사용할 수 있도록 산업 표준의 OpenType 글꼴은 물론 최근에 정의된 ClearType 기술도 지원합니다. ClearType은 최신 모니터에서 각 픽셀을 구성하는 하위 요소를 개별적으로 다듬는 기법인 하위 픽셀 위치 조정을 통해 텍스트를 보다 매끄럽게 표시하는 기술입니다. WPF는 또한 Glyphs 클래스를 통한 텍스트 렌더링 기능을 부분적으로 지원합니다. 이 클래스는 XPS 문서에서 문자를 나타내는 데 사용되며, 자세한 내용은 이 문서의 뒷부분에서 설명합니다.

WPF는 가독성을 높이기 위해 문자 그룹을 연결된 단일 이미지로 대체하는 합자 방식도 지원합니다. 예를 들어 "ffi"라는 문자 그룹은 일반적으로 인쇄 페이지에서는 이 세 문자가 들어 있는 연결된 단일 합자로 대체됩니다. 이 합자를 화면 표시 텍스트에 사용하면 사용자는 사용된 세부적인 기술은 눈치채지 못한 채 인쇄된 페이지를 보는 것처럼 텍스트를 편하게 읽을 수 있습니다.

문서

텍스트는 단추, 목록 및 사용자 인터페이스의 다른 여러 요소에 표시되므로 텍스트의 가독성을 높이는 것은 매우 바람직합니다. 그러나 텍스트는 문서에서와 같이 더 긴 단락 형식으로 표시되는 경우에 그 기능이 더 중요합니다. 따라서 화면 표시 가독성을 높이기 위해서는 문서가 표시되는 방법도 함께 개선해야 합니다. 이를 위해 WPF에서는 두 가지 유형의 문서, 즉 '고정' 문서와 '동적' 문서를 지원합니다.

고정 문서는 화면에서 렌더링할 때나 인쇄할 때의 모양이 동일합니다. 일부 양식, 법률 문서, 기타 출판물 유형 등 문서 모양을 항상 일관되게 유지해야 하는 경우에는 고정된 형식의 문서를 사용하는 것이 좋습니다. WPF에서 지원하는 고정된 형식의 문서는 XPS로 정의됩니다. XPS에 대한 자세한 내용은 이 문서의 뒷부분에서 설명합니다. 고정 문서의 내용은 XAML의 FixedDocument 요소를 사용하여 지정할 수 있습니다. 이 간단한 요소에는 PageContent 요소의 목록만 포함되고, 각 PageContent 요소에는 고정 문서에 포함된 각 페이지의 이름이 들어 있습니다. WPF에서는 DocumentViewer 컨트롤을 사용하여 고정 문서를 표시합니다. 이 컨트롤은 XPS 문서를 읽기 전용 모드로 표시하고, 사용자는 문서에서 뒤로 또는 앞으로 이동하거나 특정 텍스트를 검색하는 등의 작업을 할 수 있습니다.

고정 문서가 화면과 인쇄 용지 모두에서 사용할 수 있는 문서 유형이라면 동적 문서는 화면 표시 전용 문서입니다. 동적 문서는 문서 내용의 가독성을 최대한 높이기 위해 창 크기와 기타 요인에 따라 텍스트와 그래픽을 자동으로 조정하여 표시합니다. 고정 문서에 대한 설명을 통해 예상할 수 있듯이 동적 문서는 FlowDocument라는 XAML 요소를 사용하여 정의됩니다. 다음은 간단한 예제입니다.

  <FlowDocument 
    ColumnWidth="300" 
    IsColumnWidthFlexible="True" 
    IsHyphenationEnabled="True">
      <Paragraph FontSize="12">
       <Bold>WPF 설명</Bold>
      </Paragraph>
      <Paragraph FontSize="10">
       WPF는 .NET Framework 3.0을 위한 사용자 인터페이스 
       기술입니다. WPF는 문서, 2차원 및 3차원 그래픽, 미디어 등을 
       지원할 뿐만 아니라 최신 사용자 인터페이스를 만들기 위한 
       통합된 기반을 제공합니다. 또한 동일한 방법과 동일한 코드를 
       사용하여 독립 실행형 Windows 응용 프로그램 및 브라우저 
       내에서 실행되는 응용 프로그램을 만들 수 있도록 
       지원합니다.
      </Paragraph>
  </FlowDocument>

이 문서는 너비가 300이상인 열에 표시되도록 지정됩니다. 이때 너비는 각 픽셀이 1/96인치인 '장치 독립적 픽셀' 단위로 측정됩니다. 그러나 문서 작성자는 바로 다음 줄에 IsColumnWidthFlexible 속성을 true로 설정하여 이 너비를 변경 가능하도록 설정했습니다. 이 설정은 이 문서를 표시하는 데 사용되는 열의 개수와 너비를 WPF에서 변경할 수 있도록 허용합니다. 예를 들어 이 문서가 표시되는 창의 너비를 사용자가 변경하면 WPF에서는 문서의 텍스트를 표시하는 데 사용되는 열의 개수와 너비를 적절하게 늘리거나 줄일 수 있습니다.

다음으로 이 문서에서는 하이픈을 사용하도록 IsHyphenationEnabled 속성이 true로 설정되었습니다. 바로 아래에는 이 문서에 포함된 두 개의 단락이 나옵니다. 각 단락의 텍스트는 글꼴 크기가 서로 다르게 설정된 두 개의 Paragraph 요소 안에 각각 들어 있고 첫 번째 단락의 텍스트는 굵게 표시되도록 설정되었습니다.

WPF에서는 가독성을 높이기 위한 몇 가지 FlowDocument 옵션을 추가적으로 정의합니다. 예를 들어 IsOptimalParagraphEnabled 속성을 true로 설정하면 WPF는 단락 전체에서 공백을 가능한 한 균등하게 사용합니다. 이 속성을 사용하면 가독성을 떨어뜨리는 "연속적인" 공백이 나타나는 것을 방지할 수 있습니다. 이 방법은 인쇄된 문서에 일반적으로 사용됩니다. 동적 문서에는 일반 텍스트나 잉크(Tablet PC에 해당)에 노트를 추가하는 것과 같이 메모를 사용할 수도 있습니다. 각 메모는 문서에서 메모가 연결되어 있는 내용을 식별하는 '앵커(anchor)'와 메모 내용 자체가 들어 있는 '카고(cargo)'로 구성됩니다.

WPF에서는 다음과 같은 몇 가지 컨트롤을 사용하여 FlowDocument를 표시할 수 있습니다.

  • FlowDocumentPageViewer: 문서에서 한 번에 한 페이지씩 이동할 수 있습니다. 이 컨트롤은 앞으로/뒤로 단추 및 문서 크기를 조정하는 데 사용할 수 있는 확대/축소 컨트롤을 제공합니다.
  • FlowDocumentScrollViewer: 페이지 오른쪽에 있는 스크롤 막대를 사용하여 문서를 스크롤하는 일반적인 보기 형식으로 FlowDocument를 표시합니다.
  • FlowDocumentReader: FlowDocumentPageViewerFlowDocumentScrollViewer의 기능을 결합한 형식으로 문서를 표시합니다. 이 컨트롤을 사용하면 사용자가 동적 문서의 페이지 단위 보기(두 페이지씩 보기 포함)와 스크롤 보기 사이를 전환할 수 있습니다.

디지털 방식으로 전달되는 정보가 증가함에 따라 화면 표시 가독성도 점차 그 중요성이 높아지고 있습니다. WPF는 동적 문서를 통해 정보를 보다 효과적으로 표시함으로써 더욱 편리한 Windows 사용자 환경을 제공합니다.

이미지

회사 로고, 노을 사진 등 이미지는 많은 사용자 인터페이스의 기본 요소입니다. WPF에서 이미지는 일반적으로 Image 컨트롤을 사용하여 표시됩니다. 예를 들어 JPEG 파일을 표시하려면 다음과 같은 XAML을 사용할 수 있습니다.

<Image 
 Width="200" 
 Source="C:\Documents and Settings\All Users\Documents\
  My Pictures\Ava.jpg" />

이 예제에서는 이미지 너비를 200으로 설정합니다. 이 경우에도 장치 독립적 픽셀 단위가 사용됩니다. Source 특성은 이미지가 들어 있는 파일을 식별합니다.

이미지 파일에는 키워드, 사용자가 지정한 등급 등 이미지에 대한 정보를 나타내는 메타데이터가 들어 있으며 WPF 응용 프로그램에서는 이 정보를 읽고 기록할 수 있습니다. 회전하는 3차원 개체에 그림을 그리는 것처럼 더 재미있는 방법으로 이미지를 사용할 수도 있습니다. 이 문서에 포함된 간단한 예제에서는 가장 일반적인 이미지 사용 방법을 보여 주지만 WPF에서 이미지를 사용하는 방법은 이보다 훨씬 다양합니다.

WPF의 Image 컨트롤은 JPEG, BMP, TIFF, GIF, PNG 등의 다양한 형식뿐만 아니라 Windows Vista에 새롭게 추가된 Microsoft Windows Media Photo(WMPhoto) 형식의 이미지도 표시할 수 있습니다. 이미지 형식에 관계없이 WPF는 WIC(Windows Imaging Component)를 사용하여 이미지를 생성합니다. WIC는 위에서 언급한 모든 이미지 형식에 대한 코더/디코더(일반적으로 '코덱'이라고 함)뿐만 아니라 타사 코덱을 추가할 수 있는 프레임워크도 제공합니다.

비디오 및 오디오

네트워크 및 프로세서 속도가 빨라짐에 따라 비디오는 사용자가 소프트웨어와 상호 작용하는 방식에서 중요한 부분을 차지하게 되었습니다. 또한 사용자들은 컴퓨터에서 음악이나 기타 오디오를 듣는 데 많은 시간을 보내기도 합니다. 이러한 요구에 부응하기 위해 WPF는 비디오 및 오디오 기능을 기본적으로 제공합니다.

비디오 및 오디오 기능은 MediaElement 컨트롤을 통해 제공됩니다. 다음은 이 컨트롤을 사용하는 간단한 XAML 예제입니다.

<MediaElement 
 Source="C:\Documents and Settings\All Users\Documents\
  My Videos\Ruby.wmv" /> 

이 컨트롤은 WMV, MPEG 및 AVI 비디오와 다양한 형식의 오디오를 재생할 수 있습니다.

2차원 그래픽

지난 20년 동안 Windows용 2차원 그래픽 작성자들은 GDI(Graphics Device Interface)와 그 후속 버전인 GDI+를 사용해왔습니다. 그러나 2차원 그래픽은 사용자 인터페이스 기술에 통합되어 있지 않기 때문에 Windows Forms 응용 프로그램에서도 별도의 네임스페이스를 통해 이 기능에 액세스해야 합니다. 3차원 그래픽의 경우에는 완전히 다른 기술인 Direct3D를 사용해야 하기 때문에 작업이 더 번거로웠습니다. 그러나 WPF를 사용하면 대부분의 응용 프로그램에서 이러한 복잡한 작업 과정을 단순화할 수 있습니다. 즉, 2차원 그래픽과 3차원 그래픽 모두를 XAML에서 직접 만들거나 WPF 라이브러리를 사용하여 프로시저 코드에서 만들 수 있습니다. 이러한 작업에 사용되는 요소는 WPF의 다른 모든 요소와 마찬가지로 응용 프로그램의 시각적 트리의 일부입니다.

2D 그래픽의 경우 WPF는 응용 프로그램에서 이미지를 만드는 데 사용할 수 있도록 다음과 같은 '모양' 그룹을 정의합니다

  • Line: 두 지점 사이에 직선을 그립니다.
  • Elllipse: 타원을 그립니다.
  • Rectangle: 사각형을 그립니다.
  • Polygon: 서로 연결된 직선의 그룹으로 정의되는 닫힌 모양을 그립니다.
  • Polyline: 서로 연결된 직선의 그룹으로 정의되는 열린 모양을 그립니다.
  • Path: 임의의 경로로 표시되는 모양을 그립니다. 열린 모양이나 닫힌 모양을 사용할 수 있으며 경로에는 직선이나 곡선을 사용할 수 있습니다. Path를 사용하면 실제로 선, 타원, 사각형, 다각형, 다중선 등을 모두 그릴 수 있기 때문에 다른 모든 모양은 편의를 위해서만 제공됩니다.

이 클래스를 사용하면 간단한 그래픽을 쉽게 만들 수 있습니다. 예를 들어 다음 XAML은 빨간색 타원을 그립니다.

<Ellipse Width="30" Height="10" Fill="Red" />

모양을 채우려면 '브러시'를 사용합니다. 위의 예제에서는 기본값인 단색 브러시를 사용하지만 WPF에서는 몇 가지 다른 옵션도 제공합니다. 예를 들어 다음 예제에서는 가로 방향으로 빨간색에서 노란색으로 바뀌는 색 그라데이션으로 채워진 사각형을 정의합니다.

<Rectangle Width="30" Height="10" 
 Fill="HorizontalGradient Red Yellow" />

이 외에도 이미지, 비트맵 등을 사용하여 그리는 브러시, 수직 그라데이션 및 방사형 그라데이션을 비롯하여 여러 가지 다른 브러시를 사용할 수 있습니다. 이 문서에서 다루지는 않지만 모양에 '펜'을 사용하여 윤곽선의 색, 너비 및 스타일을 지정할 수도 있습니다.

WPF에서는 모든 요소가 공통의 기반에서 구현되므로 서로 다른 요소를 간단하게 결합할 수 있다는 점을 기억해 두십시오. 예를 들어 응용 프로그램에서는 Rectangle 안에 Image를 표시하고, Button 안에 Ellipse를 배치하는 등 다양한 방법으로 요소를 결합할 수 있습니다. 따라서 2D 그래픽을 3D 그래픽 및 다른 인터페이스 요소에 결합하는 것 역시 매우 간단합니다.

WPF는 모양 외에도 2차원 그래픽 작업에 사용할 수 있는 다른 클래스 그룹도 제공합니다. '기하 도형'이라고 하는 이러한 클래스는 모양과 여러모로 비슷합니다. Line, Rectangle, EllipsePath 같은 옵션을 제공하는 모양과 마찬가지로 이 클래스도 LineGeometry, RectangleGeometry, EllipseGeometryPathGeometry 같은 옵션을 제공합니다. 일반적으로 모양은 실제 이미지를 그리는 데 사용되고 기하 도형은 주로 영역을 정의하는 데 사용된다는 것이 이 두 클래스 간의 가장 중요한 차이점입니다. 예를 들어 정사각형 이미지를 원 안에 맞추기 위해 잘라야 할 경우 EllipseGeometry 클래스를 사용하여 원의 경계를 지정할 수 있습니다. 마찬가지로 응용 프로그램에서 마우스 클릭이 감지된 영역과 같이 적중 테스트 영역을 정의해야 하는 경우에는 해당 영역에 기하 도형을 지정하면 됩니다.

이 섹션에서 설명한 모든 내용은 실제로 '시각적 레이어'라는 하위 수준의 인터페이스를 기반으로 구현된다는 점을 알아야 합니다. 이 레이어를 직접 사용하여 그래픽, 이미지 및 텍스트를 만들 수도 있습니다. 간단한 고성능 그래픽을 만들 때와 같이 레이어를 직접 사용하는 방법이 유용할 때도 있지만 대부분의 응용 프로그램에서는 WPF가 제공하는 모양 및 다른 상위 수준의 추상화를 사용합니다.

3차원 그래픽

2차원 그래픽은 Windows 인터페이스의 일반적인 요소이기 때문에 WPF에서는 2차원 그래픽과 관련된 다양한 기술을 제공합니다. 반면, 3차원 그래픽은 뛰어난 데이터 시각화, 3D 차트, 제품 렌더링 등의 다양한 기능을 통해 상당한 가치를 제공할 수 있음에도 불구하고 아직까지는 2차원 그래픽만큼 일반화되지 않았습니다. 이전에는 3D로 작업하기 위해 주로 게임 개발자나 기타 전문 집단에서만 사용하는 고유한 기술을 사용해야 했습니다. 그러나 WPF는 3D 그래픽 기능을 표준 환경에 통합함으로써 이전과는 다른 새로운 작업 환경을 제공합니다.

WPF가 없는 경우 Windows 플랫폼에서는 Direct3D API를 사용하여 3D를 개발해야 합니다. WPF의 다른 요소와 마찬가지로 WPF의 3D 그래픽 기능은 기본적으로 Direct3D에 기반을 두고 있지만 개발자의 실제 작업 환경은 훨씬 단순해졌습니다. 이 문서의 뒷부분에서 설명하는 것처럼 WPF보다는 Direct3D를 사용하는 것이 더 적합한 경우도 있지만, Microsoft의 목표는 Windows 인터페이스에 사용할 대부분의 3D 작업에 WPF를 사용하도록 하는 것입니다.

WPF에서는 응용 프로그램에 Viewport3D 컨트롤을 사용하여 3D 그래픽을 표시합니다. 이 컨트롤은 기본적으로 응용 프로그램에서 나타내는 3차원 공간에 창을 제공합니다. Viewport3D 컨트롤은 WPF 인터페이스의 아무 곳에나 사용할 수 있기 때문에 3D 그래픽을 원하는 위치에 표시하는 것이 가능합니다.

3D 그래픽을 만들 경우 개발자는 하나 이상의 '모델'을 정의한 다음, 이러한 모델에 적용할 조명과 보기 방식을 지정합니다. 이 경우에도 XAML이나 코드 또는 두 방법을 함께 사용하여 모든 옵션을 지정할 수 있습니다. WPF에서는 모델의 모양을 정의할 수 있는 GeometryModel3D 클래스를 사용하여 모델을 정의합니다. 모델을 정의한 후에는 다양한 종류의 '재질'을 사용하여 모델의 모양을 제어할 수 있습니다. 예를 들어 SpecularMaterial 클래스는 표면에 광택 효과를 적용하지만 DiffuseMaterial 클래스는 이 효과를 적용하지 않습니다.

사용한 재질에 관계없이 다양한 방법으로 모델에 조명 효과를 적용할 수 있습니다. DirectionalLight 클래스는 특정 방향의 광원을 제공하고 AmbientLight 클래스는 전체적으로 균일한 조명을 제공합니다. 마지막으로 모델을 보는 방식을 정의하는 '카메라'를 지정합니다. 예를 들어 PerspectiveCamera를 사용하면 모델을 보는 거리와 원근감을 지정할 수 있고, OrthographicCamera를 사용하면 원근감만 제외하고 동일한 옵션을 지정할 수 있습니다. 즉, 이 경우에는 카메라에서 멀리 떨어진 개체도 더 작게 표시되지 않습니다.

XAML 또는 코드에서 직접 복잡한 3D 화면을 만드는 것은 쉽지 않습니다. 3D를 사용하는 대부분의 WPF 응용 프로그램에서 개발자는 그래픽 도구를 사용하여 필요한 정의를 생성하는 경우가 많습니다. 어떤 방법을 사용하든지 표준 사용자 인터페이스에 3D 그래픽을 사용하면 사용자에게 표시되는 화면의 품질을 크게 향상시킬 수 있습니다.

변환 및 효과

WPF에서는 개발자가 모양 및 기타 요소를 정의할 수 있을 뿐만 아니라 회전, 크기 변경 등의 작업을 통해 요소를 변환할 수도 있습니다. XAML에서는 RotateTransformScaleTransform 같은 요소를 사용하여 이러한 작업을 할 수 있습니다. 이러한 변환은 모든 사용자 인터페이스 요소에 적용할 수 있습니다. 다음은 변환 작업을 보여 주는 간단한 예제입니다.

</Button>
  <Button Content="여기를 클릭하십시오.">
   <Button.RenderTransform>
    <RotateTransform Angle="45" />
   </Button.RenderTransform>
  </Button>

RotateTransform 요소는 단추를 45도 회전시킵니다. 이 방법으로 단추를 회전시키는 것은 그다지 유용하지 않지만 이러한 기능이 있다는 것만으로 WPF 디자인의 다양성을 짐작할 수 있습니다. 사용자 인터페이스의 여러 요소는 동일한 기술에 기반을 두고 있기 때문에 여러 가지 방법으로 결합될 수 있습니다.

WPF는 몇 가지 미리 정의된 효과를 제공합니다. 변환과 마찬가지로 이러한 효과도 Buttons, ComboBoxes 등 사용자 인터페이스의 다양한 요소에 적용할 수 있습니다. 미리 정의된 효과로는 인터페이스 요소를 흐릿하게 표시하는 흐리게 효과, 요소를 빛나게 만드는 외부 글로우 효과, 인터페이스 요소 뒤에 그림자를 추가하는 그림자 효과 등이 있습니다.

애니메이션

인터페이스의 요소를 움직이게 만드는 애니메이션을 사용하면 여러 가지로 매우 유용합니다. 예를 들어 단추를 클릭할 때 단추가 실제로 눌린 것처럼 아래로 내려갔다가 다시 올라오면 훨씬 실감나는 인터페이스를 연출할 수 있습니다. 이보다 복잡한 애니메이션을 사용하여 사용자의 주의를 끌거나 이야기를 들려주는 방법으로 사용자의 참여를 유도하는 인터페이스를 만들 수 있습니다. WPF의 애니메이션 기능은 이러한 모든 효과를 지원합니다.

변환과 마찬가지로 애니메이션을 단추, 모양, 이미지 등 사용자 인터페이스의 다양한 요소에 적용할 수 있습니다. 애니메이션은 시간 흐름에 따라 개체의 속성 중 하나 이상의 속성 값을 변경하여 만듭니다. 예를 들어 EllipseHeight 속성 값을 2초 동안 조금씩 줄이면 타원이 천천히 찌그러지는 것처럼 보일 수 있습니다.

서로 관련된 애니메이션 그룹을 정의하면 유용할 수 있습니다. WPF에서 제공하는 Storyboard 클래스를 사용하면 이러한 작업을 할 수 있습니다. 각 Storyboard는 하나 이상의 '시간 표시 막대'를 포함할 수 있고, 각 시간 표시 막대는 하나 이상의 애니메이션을 포함할 수 있습니다. 제공되는 다양한 시간 표시 막대를 사용하면 애니메이션을 순차적으로 실행하거나 병렬로 실행할 수 있습니다. 다음은 Ellipse를 찌그러뜨리는 애니메이션을 보여 주는 간단한 XAML 예제입니다.

    <Ellipse Width="100" Height="50" Fill="Blue"
     Name="EllipseForSquashing">
     . . . 
     <Storyboard>
      <DoubleAnimation
       Storyboard.TargetName="EllipseForSquashing" 
       Storyboard.TargetProperty="Height"
        From="50" To="25" Duration="0:0:2" />
       </Storyboard>
       . . . 
    </Ellipse>      

앞에서 살펴본 예제에서와 마찬가지로 이 예제 역시 먼저 Ellipse를 정의합니다. 이 예제에서는 Name 속성도 함께 사용하여, 나중에 이 이름으로 Ellipse를 참조할 수 있도록 했습니다. 이 예제에는 몇 가지 세부 사항이 생략되었지만 XAML로 애니메이션을 정의하려면 Storyboard 요소가 반드시 있어야 합니다. 이 경우에는 EllipseHeight 속성이 Double 형식이기 때문에 StoryboardDoubleAnimation 요소가 들어 있습니다. 이 요소는 애니메이션을 만들 Ellipse의 이름, 변경할 속성 및 변경할 내용을 지정합니다. 이 예제에서는 Height의 값을 2초 동안 50에서 25로 변경합니다.

이 예제보다 훨씬 복잡한 애니메이션을 만들 수 있습니다. 예를 들어 애니메이션을 마우스 클릭 같은 이벤트를 통해 트리거하거나, 일시 중지했다가 다시 재생하거나, 지정한 횟수만큼(또는 계속) 반복하는 등 복잡한 애니메이션도 만들 수 있습니다. 애니메이션을 통해 개발자는 더 실감나고 사용하기 쉬우면서 보다 많은 기능을 제공하는 사용자 인터페이스를 만들 수 있습니다.

데이터 바인딩

대부분의 사용자 인터페이스는 특정한 유형의 데이터를 표시합니다. 인터페이스 개발자는 데이터 바인딩을 통해 데이터를 더 쉽게 표시할 수 있습니다. 데이터 바인딩을 사용하면 WPF 컨트롤에 표시되는 요소를 해당 컨트롤 외부에 있는 데이터와 직접 연결할 수 있습니다. 예를 들어 WPF TextBox 컨트롤의 Text 속성 값을 이 응용 프로그램의 비즈니스 논리의 일부인 Employee 개체의 Name 속성에 바인딩할 수 있습니다. 두 속성 중 하나가 변경되면 바인딩된 다른 한 속성에 해당 변경 내용이 반영됩니다. 예를 들어 사용자가 TextBox에서 값을 변경하면 Employee 개체의 Name 속성에도 변경된 값이 적용되고, 그 반대의 경우도 마찬가지로 적용됩니다.

두 개체의 속성 간에 이러한 연결을 만들려면 WPF Binding 클래스를 사용해야 합니다. 다음은 이러한 바인딩을 보여 주는 간단한 XAML 예제입니다.

<TextBox . . . >
 <TextBox.Text>
  <Binding Path="Name" />
 </TextBox.Text>
</TextBox>

이 예제에서는 Binding 요소의 Path 특성을 사용하여 TextBoxText 속성을 바인딩할 대상 속성을 식별합니다. Path는 이 속성이 속해 있는 개체(런타임에 지정됨)가 C# 또는 Visual Basic 등의 언어로 정의된 CLR(공용 언어 런타임) 개체인 경우에 사용됩니다. WPF의 데이터 바인딩 기능을 사용하면 CLR 개체는 물론 BindingXPath 속성을 사용하여 XML 데이터에 직접 연결할 수도 있습니다. 이 옵션은 지정한 데이터를 참조하는 XML 문서에서 하나 이상의 노드를 선택하는 XPath 쿼리를 만듭니다.

더 복잡한 데이터 바인딩 옵션을 사용할 수도 있습니다. 예를 들어 목록 바인딩을 사용하면 표준 IEnumerable 인터페이스를 구현하는 CLR 개체를 통해 ListBox 컨트롤에 내용을 채울 수 있습니다. 필요한 경우 데이터를 표시하기 전에 필터링 또는 정렬을 적용할 수도 있습니다. WPF에서는 ADO.NET Dataset에 바인딩할 수 있지만 관계형 데이터베이스 관리 시스템의 데이터에 직접 바인딩하는 기능은 지원하지 않습니다. 어떤 데이터 바인딩 옵션을 사용하는지에 관계없이 기본적으로 데이터 바인딩은 최대한 간단하게 사용자 인터페이스에 데이터를 표시하는 데 필요한 기능입니다.

사용자 인터페이스 자동화

WPF 인터페이스의 가장 일반적인 사용자는 당연히 사람입니다. 그러나 사용자 인터페이스를 작동하는 주체가 사람이 아니라 다른 소프트웨어인 경우도 있습니다. WPF의 UI(사용자 인터페이스) 자동화를 사용하면 이러한 방식으로 인터페이스를 작동할 수 있습니다.

예를 들어 개발자가 인터페이스를 실행하는 자동화된 스크립트를 만들어야 한다고 가정해 보겠습니다. 이 경우 개발자는 UI 자동화 기능이 제공하는 프로그래밍 방식의 액세스를 통해 사람이 실행하는 것처럼 인터페이스를 작동시키는 스크립트를 만들 수 있습니다. UI 자동화는 인터페이스의 다양한 요소를 음성으로 읽어 주는 도구와 같은 내게 필요한 옵션 도구를 만드는 데도 유용합니다. UI 자동화를 사용하면 이러한 요소가 들어 있는 트리에서 각 요소를 프로그래밍 방식으로 하나씩 실행할 수 있기 때문에 이러한 종류의 도구를 만들 수 있는 것입니다.

WPF에서는 UI 자동화를 사용하기 위해 UI 자동화 트리를 만듭니다. 이 트리는 인터페이스의 각 요소를 나타내는 일련의 AutomationElement 개체로 구성됩니다. 이 트리의 루트는 Desktop이고, 열려 있는 각 응용 프로그램은 이 루트의 자식이 됩니다. 트리는 각 응용 프로그램으로 세분화되고 각 WPF 컨트롤은 AutomationElement 개체 하나로 표시되거나, 경우에 따라 둘 이상의 개체로 표시됩니다. 이 경우 프로그래밍 방식으로 인터페이스에 액세스할 수 있도록 사용자가 상호 작용할 수 있는 모든 요소가 고유한 AutomationElement로 나타납니다. 예를 들어 단추가 여러 개 포함된 컨트롤에는 컨트롤 자체와 각각 고유한 AutomationElement 개체로 표시되는 단추가 모두 있습니다. 이와 같이 세분화된 UI 자동화 트리를 만들면 테스트 스크립트, 내게 필요한 옵션 도구 등의 클라이언트 응용 프로그램이 인터페이스의 각 구성 요소를 사람이 실제 사용하는 것처럼 액세스할 수 있습니다.

UI 자동화가 WPF의 핵심적인 기능은 아니며 대다수의 일반 사용자들은 이 기능을 거의 사용하지 않을 수도 있습니다. 그러나 소프트웨어 테스트 담당자나 움직임이 불편한 사용자와 같이 이를 필요로 하는 사용자들에게는 '없어서는 안 될' 중요한 기능입니다. 다수의 사용자들이 사용하는 기능만 중요한 것은 아닙니다.

Windows Presentation Foundation 적용

WPF에는 방대한 양의 기술이 포함되어 있습니다. 이러한 모든 기술이 사용자와의 상호 작용과 관련이 있지만 가장 많이 적용되는 세 가지 영역으로는 독립 실행형 WPF 응용 프로그램, XBAP 및 XPS 문서가 있습니다. 이 섹션에서는 이 세 가지 영역을 자세하게 살펴봅니다.

독립 실행형 WPF 응용 프로그램

WPF를 사용하는 가장 일반적인 방법은 독립 실행형 응용 프로그램에 사용하는 것입니다. 독립 실행형 WPF 응용 프로그램은 다른 일반적인 Windows 응용 프로그램처럼 실행되며 웹 브라우저를 사용하지 않습니다. 이러한 이유로 독립 실행형 응용 프로그램에는 완전한 신뢰 수준이 부여되고 WPF의 모든 기능을 사용할 수 있습니다. 완전 신뢰란 독립 실행형 WPF 응용 프로그램이 컴퓨터에 설치되어 있는 WCF(Windows Communication Foundation) 등의 다른 서비스를 자유롭게 사용할 수 있음을 의미합니다.

다른 Windows 응용 프로그램과 마찬가지로 독립 실행형 WPF 응용 프로그램을 로컬 디스크 또는 네트워크 서버에서 설치할 수 있으며 .NET Framework의 기능인 ClickOnce를 사용하여 설치할 수도 있습니다. ClickOnce는 사용자가 Internet Explorer를 통해 Windows 응용 프로그램(WPF 응용 프로그램 포함)을 다운로드하여 설치한 후 해당 응용 프로그램의 업데이트가 릴리스될 때 이를 자동으로 설치할 수 있게 해 주는 간단한 방법을 제공합니다.

XAML 브라우저 응용 프로그램: XBAP

독립 실행형 WPF 응용 프로그램이 대부분의 기능을 제공하지만 모든 경우에 적합한 것은 아닙니다. 클라이언트를 Windows 응용 프로그램으로 실행하는 것보다 웹 브라우저에서 실행하는 것이 더 적절한 경우도 많이 있습니다. WPF는 이러한 클라이언트에서도 최신 사용자 인터페이스를 사용할 수 있도록 XBAP를 제공합니다.

다음 그림에서 볼 수 있는 것처럼 XBAP는 Internet Explorer에서 실행됩니다. XBAP는 ASP.NET, JSP(JavaServer Pages) 및 기타 웹 기술을 사용하여 만든 웹 응용 프로그램의 클라이언트로 동작합니다. XBAP는 HTTP 또는 SOAP를 사용하여 이러한 웹 응용 프로그램과 통신할 수 있습니다. XBAP는 서버 플랫폼에 관계없이 항상 ClickOnce를 통해 로드되며 이 과정에서 사용자에게 대화 상자나 메시지를 전혀 표시하지 않고 일반적인 웹 페이지처럼 로드됩니다. 이러한 이유로 XBAP는 시작 메뉴나 프로그램 추가/제거에 표시되지 않습니다.

그림 7. Internet Explorer에서 실행되는 XBAP

일반적으로 XBAP는 탐색 형식의 인터페이스를 제공하지만 이는 선택 사항입니다. 탐색 형식의 인터페이스를 사용하면 사용자에게 익숙한 기존의 웹 클라이언트처럼 응용 프로그램을 실행할 수 있습니다. Internet Explorer 7에서는 XBAP가 브라우저의 기본 앞으로/뒤로 단추를 사용하고, 사용자가 액세스하는 XAML 페이지는 브라우저의 기록 목록에 나타납니다. 그러나 Internet Explorer 6에서는 XBAP가 자체적인 앞으로/뒤로 단추와 별도의 기록 목록을 사용합니다. XBAP는 현재의 실행 환경을 자동으로 파악하여 적절한 방식으로 동작하기 때문에 개발자는 개별 브라우저별로 버전을 만들지 않아도 됩니다.

XBAP는 웹에서 로드되어 브라우저에서 실행되기 때문에 .NET Framework의 코드 액세스 보안 기능이 부여하는 제한된 신뢰 수준에서만 실행됩니다. 이러한 이유 때문에 독립 실행형 WPF 응용 프로그램에서 사용할 수 있는 기능 중 일부를 XBAP에서는 사용하지 못할 수 있습니다. 예를 들어 인터넷 영역에서 배포된 XBAP에서는 다음과 같은 기능을 사용할 수 없습니다.

  • 독립 실행형 창 만들기
  • 응용 프로그램에서 정의한 대화 상자 표시
  • XBAP 자체에서 시작한 저장 대화 상자 표시
  • 제한적으로 사용할 수 있는 격리된 저장소 영역 이외의 파일 시스템에 액세스
  • UI 자동화 클라이언트로 동작
  • WCF 사용. WCF 응용 프로그램을 사용하려면 완전 신뢰 수준이 필요하기 때문에 인터넷에서 배포된 XBAP는 이 응용 프로그램을 사용할 수 없습니다. 대신에 ASMX라고 하는 ASP.NET 웹 서비스를 사용하여 원래 로드된 위치의 웹 응용 프로그램과 통신할 수 있습니다.
  • Windows Forms, MFC(Microsoft Foundation Class) 또는 Win32 직접 호출을 통해 만든 사용자 인터페이스 코드 사용. 다음 섹션에서 설명하는 것처럼 독립 실행형 WPF 응용 프로그램은 이러한 모든 이전 기술과 상호 운용될 수 있지만 신뢰 수준이 제한된 XBAP 환경에서는 여기에 나열된 기술 중 어떤 것도 사용할 수 없습니다.
  • 비관리 코드 사용

앞에서 살펴본 것처럼 독립 실행형 WPF 응용 프로그램 및 XBAP 모두에 동일한 코드 베이스를 사용할 수 있습니다. 이를 위해 개발자는 XBAP에서 사용할 수 없는 모든 기능을 ifdef에 래핑하여 조건부 컴파일을 사용할 수 있습니다. XBAP 버전에서는 문서 표시, 2차원 및 3차원 그래픽 사용, 비디오와 오디오 재생 등 독립 실행형 응용 프로그램 버전에서 사용할 수 있는 대부분의 기능을 동일하게 수행할 수 있을 뿐만 아니라 XBAP가 실행되고 있는 컴퓨터의 그래픽 하드웨어를 활용할 수도 있습니다.

Internet Explorer에는 XBAP뿐만 아니라 순수 XAML 페이지도 직접 표시할 수 있습니다. 'XAML 사용 완화'라고 하는 이러한 페이지는 브라우저에 정적 페이지를 표시할 때 유용합니다. 그러나 이벤트를 처리하려면 코드를 사용해야 하므로 결과적으로 XBAP를 만들어야 합니다.

개발자는 XBAP를 사용하여 브라우저 응용 프로그램에서 WPF 기능의 대부분을 사용할 수 있습니다. 또한 XBAP를 사용하면 독립 실행형 응용 프로그램과 브라우저 응용 프로그램에 코드가 거의 유사한 공통적인 프로그래밍 모델을 사용할 수 있습니다. 해당 클라이언트가 최신 Windows 플랫폼에서 실행되도록 디자인된 웹 응용 프로그램의 경우에는 XBAP를 사용하는 것이 좋습니다.

XPS 문서

XPS 문서는 WPF 환경에 사용되는 고정된 형식의 문서로, 사용자 인터페이스에서 매우 중요한 역할을 합니다. 앞에서 살펴본 것처럼 WPF는 DocumentViewer 컨트롤을 사용하여 XPS 문서를 표시합니다. 이 컨트롤을 WPF에 포함해야 하는 이유는 쉽게 이해할 수 있지만 XPS 자체를 WPF의 일부로 간주해야 하는 이유는 납득하기 어렵습니다. 실제로 XPS 사양에는 고정된 형식의 문서를 정의하기 위한 상당히 구체적인 방법이 명시되어 있으며, 이러한 문서는 다양한 방법으로 사용될 수 있습니다. 반면, WPF의 다른 모든 기능은 사용자 인터페이스를 만드는 데만 초점이 맞춰져 있습니다. 이와 같은 특징을 고려할 때 사용 범위가 더 넓은 XPS를 WPF라는 틀 안에 포함하는 것에 의문이 생길 수 있습니다.

XPS를 WPF의 일부로 보는 한 가지 중요한 이유는 XPS 문서가 XAML을 사용하여 정의된다는 점입니다. 레이아웃을 지정하는 Canvas 요소, 텍스트를 나타내는 Glyphs 요소, 2차원 그래픽을 만드는 Path 요소 등을 포함하여 XAML의 일부만 제한적으로 사용되지만 사실상 모든 XPS 문서는 XAML 문서입니다. 이 점을 고려하면 XPS를 WPF의 일부로 볼 수도 있습니다.

그러나 화면 표시 사용자 인터페이스는 XPS가 제공하는 핵심적인 기능과는 여전히 거리가 멉니다. Windows Vista부터는 XPS가 Windows의 기본 인쇄 형식으로 사용됩니다. XPS는 페이지 설명 언어로 사용되기 때문에 XPS를 지원하는 프린터에서 XPS 문서를 직접 렌더링할 수 있습니다. 따라서 화면 작업에서 프린터 작업에 이르는 모든 과정에서 XAML이라는 단일 설명 형식을 사용할 수 있습니다. 또한 XPS는 Windows에서 사용하던 기존의 GDI 기반 인쇄 방식을 향상시키므로 투명도 및 그라데이션과 같은 고급 그래픽 효과를 보다 정확하게 인쇄할 수 있습니다.

XPS 문서에는 XAML을 비롯하여 다양한 형식의 이미지(JPEG, PNG, TIFF 및 WMPhoto), 글꼴 데이터, 문서 구조에 대한 정보 등의 이진 데이터가 포함될 수 있습니다. 또한 필요한 경우 W3C XML 서명 정의 및 X.509 인증서를 사용하여 XPS 문서에 디지털 서명을 추가할 수도 있습니다. 모든 XSP 문서는 어떤 정보를 포함하는지에 관계없이 OPC(Open Packaging Convention)에서 정의하는 형식으로 저장됩니다. OPC는 XPS나 XAML 문서뿐만 아니라 XML 문서를 구성하는 여러 요소 간의 관계 및 이들 요소가 표준 ZIP 형식으로 저장되는 방법 등을 지정합니다. Microsoft Office 2007에서는 XML 형식에도 OPC를 사용하기 때문에 이 두 가지 형식의 문서 간에는 어느 정도의 공통점이 존재합니다.

앞에서 설명했듯이 WPF 응용 프로그램 사용자는 WPF DocumentViewer 컨트롤을 통해 XPS 문서를 볼 수 있습니다. Microsoft에서는 다음 그림에서 볼 수 있는 것처럼 DocumentViewer 컨트롤을 기반으로 하는 XPS 뷰어 응용 프로그램도 제공합니다. 이 응용 프로그램을 사용하면 컨트롤과 마찬가지로 문서에서 한 페이지씩 이동하고, 텍스트를 검색하는 등의 작업을 할 수 있습니다. XPS 문서는 사용 범위가 Windows로 제한되지 않기 때문에 Microsoft에서는 Apple Macintosh 같은 다른 플랫폼에서도 사용할 수 있는 XPS 뷰어를 제공할 예정입니다.

그림 8. XPS 뷰어를 사용하면 XPS 문서를 한 번에 한 페이지씩 읽을 수 있습니다.

WPF는 개발자가 XPS 문서를 만들고 로드하고 조작하는 데 사용할 수 있는 API 집합을 제공합니다. WPF 응용 프로그램에서도 OPC 수준의 문서를 사용할 수 있기 때문에 일반화된 방식으로 XPS 문서, Office 2007 문서 등에 액세스할 수 있습니다. Microsoft Windows Workflow Foundation을 사용하여 만든 응용 프로그램에서도 이러한 API를 통해 XPS 문서를 사용하는 워크플로를 만들 수 있습니다.

WPF는 응용 프로그램에서 고정된 형식의 문서를 표시하고 사용할 수 있도록 허용함으로써 최신 사용자 인터페이스의 구성 요소를 WPF가 지향하는 일관된 환경에 통합합니다. Windows Vista에서는 이와 동일한 형식으로 문서를 인쇄할 수 있기 때문에 화면에 표시되는 내용과 인쇄된 용지에 표시되는 내용 간의 일관성이 향상됩니다. XSP 문서 형식이 사용자 인터페이스에서 가장 중요한 기술은 아닐 수도 있지만 광범위하게 사용되는 XPS를 통해 WPF 기술이 얼마나 포괄적으로 사용되는지 그 범위를 단적으로 알 수 있습니다.

Windows Presentation Foundation 도구

WPF는 개발자가 유용하게 사용할 수 있는 다양한 기능을 제공합니다. 아무리 강력한 기술도 유용한 도구가 없다면 효용성이 떨어질 수 있습니다. Microsoft에서는 WPF를 사용하는 개발자와 디자이너에 각각 맞추어 최적화된 도구를 제공합니다. 이 섹션에서는 이 두 가지 도구에 대해 간략하게 설명합니다.

개발자용: Visual Studio

Visual Studio는 소프트웨어 개발자를 위한 Microsoft의 주력 응용 프로그램입니다. WPF의 최초 릴리스에는 개발자가 WPF 응용 프로그램을 만드는 데 사용할 수 있는 Visual Studio 2005 확장 기능이 함께 제공될 예정입니다. Visual Studio의 다음 릴리스(코드 이름: "Orcas")에는 Visual Designer for WPF(코드 이름: "Cider") 등의 다른 기능도 추가될 것입니다. 개발자는 이 비주얼 도구를 사용하여 WPF 인터페이스를 그래픽 방식으로 만든 후 기본적인 XAML을 자동으로 생성시킬 수 있습니다. 공식 릴리스 날짜는 아직 발표되지 않았지만 Orcas는 2007년 중에 출시될 예정입니다.

디자이너용: Expression Interactive Designer

앞에서 살펴본 것처럼 WPF의 기본적인 목표는 사용자 인터페이스를 만드는 작업에 디자이너가 적극적으로 참여할 수 있는 작업 환경을 만드는 것입니다. 이와 같은 목표는 XAML을 통해 실현할 수 있지만 새 작업 환경에서 디자이너가 작업하는 데 사용할 수 있는 도구가 필요합니다. 이를 위해 Microsoft에서는 Expression Interactive Designer를 만들었습니다.

아래의 스크린 샷에서 볼 수 있는 것처럼 Expression Interactive Designer는 사용자가 편리하게 작업할 수 있도록 가장 일반적인 디자인 도구 인터페이스를 제공합니다. 그러나 Designer는 WPF 응용 프로그램용 인터페이스를 만드는 데만 초점을 두어 설계되었습니다. 실제로 이 도구의 인터페이스도 WPF를 사용하여 만든 것입니다. 예를 들어 아래 화면에서 오른쪽 상단에 표시되는 WPF 컨트롤 목록과 맨 아래의 그래픽 시간 표시 막대가 이러한 인터페이스에 해당됩니다. 이러한 모든 특징은 이 문서의 앞부분에서 설명한 WPF 기능을 그대로 구현한 것으로, 인터페이스 디자이너가 자유롭게 사용할 수 있도록 설계되었습니다. 이 도구를 사용하면 애니메이션은 물론 변환, 효과 등의 다양한 기능을 그래픽 방식으로 만들 수 있습니다. 디자이너의 작업 결과는 자동으로 생성되는 XAML 파일 형식으로 저장되어 나중에 Visual Studio로 가져올 수 있습니다.

그림 9. 디자이너는 Expression Interactive Designer에서 WPF 인터페이스(그림 8)를 만들 수 있습니다.

Expression Interactive Designer는 Microsoft Expression 제품군의 세 가지 제품 중 하나입니다. 나머지 두 제품은 표준 기반 웹 인터페이스를 만드는 도구인 Expression Web Designer와 벡터 및/또는 비트맵 이미지를 만드는 도구인 Expression Graphic Designer입니다. 이 세 가지 응용 프로그램 중에서 Expression Interactive Designer만 WPF 응용 프로그램용 사용자 인터페이스를 만드는 데만 초점을 두어 설계되었습니다. Expression Graphic Designer에서 인터페이스의 GIF 이미지를 만드는 것처럼 나머지 두 제품을 사용하여 사용자 인터페이스의 구성 요소를 만들 수도 있지만 이 둘은 WPF 전용 도구가 아닙니다. 날짜는 아직 발표되지 않았지만 모든 Expression 도구는 WPF의 릴리스 이후에 출시될 예정입니다.

Windows Presentation Foundation 및 기타 Microsoft 기술

대부분의 Microsoft 신기술과 마찬가지로 WPF는 Windows 작업 환경의 다른 영역에 영향을 줍니다. 그러나 WPF 기술이 다른 영역에 미치는 영향을 살펴보기 전에 알아야 할 것은 시스템에 WPF를 설치해도 Windows Forms, MFC 등과 같이 기존의 다른 기술을 사용하는 소프트웨어와의 충돌이 발생하지 않는다는 점입니다. 즉 .NET Framework 3.0을 지원하는 시스템용으로 작성하는 새 응용 프로그램의 인터페이스는 대부분 WPF를 사용하여 만들지만 이전 기술을 사용하는 응용 프로그램도 이전과 마찬가지로 계속 실행할 수 있습니다.

Windows Presentation Foundation과 Windows Forms

.NET Framework의 최초 릴리스 이후 Windows Forms는 수많은 응용 프로그램을 만드는 데 사용되어 왔으며 WPF가 릴리스된 이후에도 일부 응용 프로그램에는 Windows Forms가 계속 사용될 것입니다. 예를 들어 이전 버전의 Windows와 같이 WPF를 사용할 수 없는 시스템에서 실행해야 하는 모든 구성 요소의 사용자 인터페이스는 Windows Forms를 사용하여 만들게 됩니다. Windows Forms가 제공하는 광범위한 컨트롤 집합을 사용하려는 경우와 같이 새 응용 프로그램에서도 필요에 따라 WPF 대신 Windows Forms를 사용할 수도 있습니다.

WPF를 사용하여 만든 응용 프로그램에서도 Windows Forms의 기능 중 일부를 활용하는 것이 유용할 수 있습니다. 예를 들어 Windows Forms는 WPF에 비해 더 많은 수의 컨트롤 집합을 제공합니다. .NET Framework 버전 2.0에 포함된 DataGridView 컨트롤의 경우 WPF에는 이 컨트롤을 대체할 수 있는 컨트롤이 없으며, 타사에서 다른 여러 가지 용도로 만든 Windows Forms 컨트롤도 상당히 많습니다. 경우에 따라서는 WPF 응용 프로그램에 이러한 기존 컨트롤을 사용해야 할 수도 있습니다. 이와는 반대로 WPF에도 3D 그래픽, 애니메이션 등 Windows Forms에서는 제공하지 않는 많은 기능이 있습니다. 이 경우에는 기존의 Windows Forms 응용 프로그램에 WPF의 기능을 통합하는 것이 좋습니다.

이러한 상호 보완은 충분히 가능합니다. 즉, WPF 응용 프로그램에서 Windows Forms 컨트롤을 호스팅하고 Windows Forms 응용 프로그램에서 WPF 컨트롤을 호스팅할 수 있습니다. 이렇게 하면 사용자는 한 응용 프로그램에서 WPF 대화 상자 및 Windows Forms 대화 상자를 별다른 불편 없이 사용할 수 있습니다.

WPF 응용 프로그램에서는 WPF의 WindowsFormsHost 컨트롤을 사용하여 Windows Forms 컨트롤을 호스팅합니다. 컨트롤의 이름에서 알 수 있듯이 이 컨트롤은 Windows Forms 컨트롤을 호스팅하여 WPF 응용 프로그램에서 Windows Forms 컨트롤을 사용할 수 있게 해 줍니다. 이 컨트롤은 ActiveX 컨트롤도 호스팅할 수 있기 때문에 이전 기술을 사용하여 만든 기존의 대규모 라이브러리를 WPF 응용 프로그램에서 액세스할 수 있습니다. 마찬가지로 Windows Forms 응용 프로그램에서는 WPF 컨트롤, 패널 및 기타 요소를 호스팅할 수 있는 Windows Forms 컨트롤인 ElementHost 컨트롤을 사용합니다. 이러한 각각의 기술을 구현하는 도구에서도 Windows Forms와 WPF용으로 작성된 소프트웨어를 모두 사용할 수 있습니다. 즉 WPF용 Visual Designer를 사용하여 Windows Forms 컨트롤을 배치하고, 마찬가지로 Windows Forms 디자이너를 사용하여 WPF 컨트롤을 배치할 수 있습니다.

그러나 WPF와 Windows Forms를 함께 사용할 경우 몇 가지 제한 사항도 있습니다. 예를 들어 WPF 컨트롤을 Windows Forms 컨트롤 위에 배치할 수는 없습니다. Windows Forms 컨트롤은 항상 최상위 계층에서 사용됩니다. WPF의 투명 효과나 변환 기능은 Windows Forms 컨트롤에 사용할 수 없습니다. 또한 WindowsFormsHostElementHost 컨트롤을 사용하려면 완전한 신뢰 수준이 필요하기 때문에 이러한 컨트롤을 사용하는 WPF 응용 프로그램을 XBAP로 실행할 수 없습니다. 그러나 대부분의 Windows 응용 프로그램의 사용자 인터페이스는 WPF와 Windows Forms를 함께 사용하여 만들 수 있습니다.

Windows Presentation Foundation과 Win32/MFC

2002년 .NET Framework가 출시되기 전에는 일반적으로 Windows 개발자가 Win32 API를 직접 호출하거나, 이 API를 래핑할 수 있는 C++ 래퍼를 제공하는 MFC를 사용하여 사용자 인터페이스를 만들었습니다. 따라서 이 방식으로 만든 인터페이스의 코드는 지금까지도 많이 사용되고 있습니다. WPF 환경에서는 이 코드가 어떻게 사용될까요?

이 질문에 대한 대답은 Windows Forms의 경우와 유사합니다. 즉, 기존 Win32/MFC 코드에서 WPF 컨트롤을 호스팅하는 것이 가능하고, WPF에서 기존 Win32/MFC 컨트롤을 호스팅하는 것도 가능합니다. 실제로 WPF와 Windows Forms 간의 상호 운용에 사용되는 기능은 Win32/MFC 상호 운용성 서비스를 기반으로 만들어졌습니다. WPF에서는 WPF 환경에서 Win32/MFC 컨트롤을 사용하는 데 필요한 HwndHost 클래스와 Win32/MFC 응용 프로그램에서 WPF 컨트롤을 사용하는 데 필요한 HwndSource 클래스를 제공합니다. 각 클래스는 필요에 따라 두 기술을 매핑합니다. 예를 들어 HwndHost는 Win32/MFC 컨트롤을 참조하는 데 사용되는 hWnd를 WPF 컨트롤인 것처럼 표시하고, 반대로 HwndSource는 WPF 컨트롤을 hWnd인 것처럼 표시합니다.

그러나 Windows Forms의 경우와 마찬가지로 이 두 환경을 함께 사용하는 경우에도 몇 가지 제약이 따릅니다. 실제로 Windows Forms 상호 운용성은 HwndHostHwndSource를 기반으로 하기 때문에 레이어 및 투명 효과에 대한 제약 등과 같이 앞에서 Windows Forms 컨트롤에 대해 설명한 모든 제한 사항이 이 경우에도 동일하게 적용됩니다. 또한 Windows Forms와는 달리 WPF와 Win32/MFC 코드를 함께 사용하는 응용 프로그램에서는 WPF의 관리 코드 환경과 Win32의 비관리 코드 환경 간의 상호 운용으로 인한 문제도 발생합니다. 이와 같은 모든 이유 때문에 Win32/MFC 코드를 사용하는 WPF 응용 프로그램은 XBAP로 실행할 수 없습니다. 그러나 앞에서 설명한 것과 마찬가지로 중요한 것은 Windows 응용 프로그램에서 WPF와 Win32/MFC를 함께 사용할 수 있다는 사실입니다. 즉, WPF를 사용하더라도 응용 프로그램의 기존 사용자 인터페이스 코드를 모두 버릴 필요는 없습니다.

Windows Presentation Foundation과 Direct3D

Direct3D는 Microsoft DirectX API 제품군의 일부로, 3차원 그래픽을 만드는 Windows 개발자들이 주로 사용하는 제품으로서 WPF가 출시된 이후에도 독자적인 가치를 제공할 것입니다. 앞에서 설명한 것처럼 실제로 WPF는 Direct3D를 통해 모든 렌더링 작업을 수행합니다. WPF의 출시 이후에 달라지는 것은 이제는 WPF에서도 3D 그래픽을 만들 수 있기 때문에 3D 개발자들이 둘 중 하나를 선택해야 한다는 점입니다.

그러나 이러한 결정은 비교적 쉽게 내릴 수 있을 것입니다. 고도의 과학적 시각화가 요구되는 3D 중심의 기술적인 응용 프로그램, 게임 등과 같이 3D를 집중적으로 개발해야 하는 경우에는 Direct3D를 사용하는 것이 좋습니다. WPF는 이러한 유형의 소프트웨어를 개발하기 위해 디자인된 플랫폼이 아니므로 적어도 WPF의 초기 릴리스는 이러한 용도로 사용하기에 적합하지 않습니다.

대신 WPF를 사용하면 전문적인 지식이 없는 일반 사용자들도 비교적 쉽게 3D 그래픽을 만들 수 있습니다. 또한 WPF 환경에서는 XBAP를 통해 웹에서 3D 그래픽을 사용할 수 있을 뿐만 아니라 2차원 그래픽과 문서를 비롯하여 응용 프로그램 사용자 인터페이스의 다른 여러 요소에 3D 그래픽을 통합할 수 있습니다. 앞에서 살펴본 HwndHost 클래스를 통해 WPF 응용 프로그램에서 Direct3D 코드를 호스팅할 수도 있습니다. WPF와 Direct3D는 각자 독자적인 가치를 제공하며 앞으로도 Windows 플랫폼에서 중심적인 기능을 할 것입니다.

Windows Presentation Foundation과 AJAX/"Atlas"

개발자는 AJAX를 사용하여 응답 성능이 뛰어난 브라우저 클라이언트를 만들 수 있습니다. AJAX를 사용하면 요청이 있을 때마다 페이지를 새로 고치지 않고도 응용 프로그램과 상호 작용할 수 있기 때문에 웹 브라우저와 웹 서버 사이의 데이터 교환 작업을 줄일 수 있습니다. AJAX는 브라우저에서 지원하는 XMLHttpRequest 개체를 사용하여 이 기능을 제공합니다. 이러한 개념은 1990년대 후반 Internet Explorer 5.0에 처음 소개되었으며 2000년대 중반에 이르러서는 더 많은 브라우저에서 XMLHttpRequest를 지원하게 되었고 AJAX가 보편화되었습니다.

그러나 AJAX 클라이언트를 만드는 작업은 그리 간단하지 않습니다. Microsoft는 이 작업을 위해 "Atlas"라는 코드 이름의 기술 집합을 만들었습니다. Atlas는 AJAX 응용 프로그램을 만드는 데 사용할 수 있는 라이브러리, 컨트롤 및 기타 요소의 집합으로, Internet Explorer뿐 아니라 다른 여러 브라우저에 사용할 수 있는 클라이언트 스크립트 라이브러리 및 서버 쪽에서 사용할 수 있는 ASP.NET 확장 기능으로 구성됩니다. Atlas는 AJAX 클라이언트가 포함된 웹 응용 프로그램을 보다 간단하게 만들 수 있도록 도와 줍니다.

AJAX는 다양한 브라우저에서 사용할 수 있다는 점에서 많은 개발자들이 관심을 갖는 기술입니다. AJAX를 사용하면 보다 뛰어난 대화형 인터페이스를 만들어 웹 사용자에게 제공할 수 있지만 지원되는 콘텐츠 형식이 매우 제한적이라는 단점이 있습니다. 예를 들어 AJAX만으로는 그래픽, 비디오, 애니메이션 및 기타 최신 상호 작용 방식을 지원할 수 없습니다. 따라서 해당 클라이언트에서 WPF를 지원하도록 해야 하는 응용 프로그램을 만들려면 AJAX 대신 XBAP를 선택하는 것이 좋습니다.

Windows Presentation Foundation과 "WPF/E"

XBAP를 사용하면 웹 응용 프로그램에서 WPF 기능의 대부분을 구현할 수 있지만 이를 위해서는 클라이언트 컴퓨터에 WPF가 설치되어 있어야 하므로 웹 응용 프로그램의 사용 범위가 제한될 수 있습니다. 또한 WPF를 지원하지 않는 Macintosh나 기타 시스템에서도 액세스할 수 있고 최신 인터페이스를 제공하는 웹 응용 프로그램을 만들어야 하는 경우가 생길 수도 있습니다.

코드 이름 "WPF/E"는 이와 같은 문제를 해결하기 위해 곧 제공될 기술입니다. WPF/E("E"는 Everywhere를 나타냄)는 Macintosh와 같은 다양한 클라이언트 플랫폼, 소형 장치 등을 비롯하여 Internet Explorer, FireFox, Netscape 등의 다양한 웹 브라우저에 WPF의 기능 중 일부를 제공할 예정으로, 여기에는 2차원 그래픽, 이미지, 비디오, 메모 및 텍스트가 포함됩니다. 그러나 XBAP에서 지원하는 기능 중 3차원 그래픽, 문서, 하드웨어 가속 등의 일부 기능은 WPF/E에서 지원되지 않습니다.

개발자는 JavaScript를 사용하여 WPF/E 응용 프로그램을 만들 수 있습니다. C# 및 Visual Basic 언어를 사용하여 개발할 수 있도록 WPF/E에는 .NET Framework의 플랫폼 간 호환 기능 중 일부도 포함될 것입니다. WPF/E는 .NET Framework 3.0의 일부가 아니며 2007년 중에 릴리스될 것으로 예상됩니다. WPF/E가 릴리스되면 웹 응용 프로그램 작성자는 광범위한 플랫폼에서 다양한 기능을 사용하여 클라이언트 응용 프로그램을 만들 수 있는 또 다른 기술을 경험할 수 있을 것입니다.

결론

사용자 인터페이스는 대부분의 응용 프로그램에서 매우 중요한 부분을 차지합니다. 효과적인 인터페이스를 만들면 사용자 및 사용자가 속한 조직에 상당한 이점을 제공할 수 있습니다. WPF의 기본적인 목표는 개발자가 이러한 효과적인 사용자 인터페이스를 만들 수 있도록 돕는 것이기 때문에 WPF는 Windows 응용 프로그램을 만드는 개발자나 일반 사용자 모두가 기대할 만한 기술입니다.

WPF는 최신 사용자 인터페이스를 만들기 위한 통합 플랫폼을 제공하고, 이러한 인터페이스를 만드는 작업에 디자이너가 보다 적극적으로 참여할 수 있도록 도와 주며, 독립 실행형 응용 프로그램과 브라우저 응용 프로그램을 위한 공통적인 프로그래밍 모델을 제공함으로써 Windows 사용자 환경을 크게 향상시키는 것을 목표로 합니다. WPF는 지난 20년 동안 Windows 사용자 인터페이스의 기반이 되어 온 기술을 대체하는 새로운 기술을 제시하여 향후 20년 동안 사용할 기반 기술로서의 역할을 할 것입니다.

  • SharePoint Search 테스트 시나리오
  1. 아래 그림과 같이 인코딩 형식을 유니코드(UTF-8) 형식으로 저장한 eml 파일과

    한국어(EUC-KR) 형식으로 저장한 eml 파일이 있습니다.   

 

  1. 위 2가지 형태로 저장한 eml 파일을 Document Library에 업로드합니다.

    (Document Library 뿐만 아니라 그 외 Custom List의 Attachment에 업로드 후 테스트 결과 동일하였음. => 리스트 상관 없음)

     

  2. 중앙 관리 사이트(SSP-검색관리)에 크롤링 작업을 한 후, 해당 문서에 대해 검색을 해보면 아래 이미지와 같이

    한글이 깨지는 현상이 일어납니다. (아래 검색 결과 페이지의 첫 번째 문서는 UTF-8 인코딩 형식으로 저장된 문서입니다.)

 

  • 크롤링 로그 확인
  1. 중앙 관리 사이트(SSP-검색관리)에 크롤링 로그를 확인하여 보면, 해당 문서에 대해서 크롤링 작업 상태 유형은 성공으로 되었으나,

    아래와 같이 "The document contains invalid utf-8 encoded characters" 라는 메시지가 나와 있습니다.

  2. 해당 메시지가 나온 문서에 대해서는 검색 시 한글이 깨져 표시 됩니다.

    현재 이 유니코드(UTF-8)파일이 아닌 문서에 대한 크롤링 문제 해결 방안을 찾고 있습니다.

I have been asked to provide some MIME for 2003 servers so we thought it was best to provide a fairly complete list.
The following MIME extensions can be added to IIS on Windows 2003

MIME Maps Extension Type

.323 text/h323
.3gp audio/3gpp
.3gp video/3gpp
.IVF video/x-ivf
.Mtx Application/metastream
.aaf application/octet-stream
.aca application/octet-stream
.ace application/x-compressed
.acx application/internet-property-stream
.aer Application/atmosphere
.afm application/octet-stream
.ai application/postscript
.aif audio/x-aiff
.aifc audio/aiff
.aiff audio/aiff
.application application/x-ms-application
.art image/x-jg
.as text/plain
.asd application/octet-stream
.asf video/x-ms-asf
.asi application/octet-stream
.asm text/plain
.asr video/x-ms-asf
.asx video/x-ms-asf
.au audio/basic
.avi video/x-msvideo
.axs application/olescript
.bas text/plain
.bcpio application/x-bcpio
.bin application/octet-stream
.bmp image/bmp
.c text/plain
.cab application/octet-stream
.cat application/vnd.ms-pki.seccat
.cdf application/x-cdf
.cfg 3DVista CFG
.chm application/octet-stream
.class application/x-java-applet
.clp application/x-msclip
.cmx image/x-cmx
.cnf text/plain
.co application/x-cult3d-object
.cod image/cis-cod
.cpio application/x-cpio
.cpp text/plain
.crd application/x-mscardfile
.crl application/pkix-crl
.crt application/x-x509-ca-cert
.csh application/x-csh
.css text/css
.csv application/octet-stream
.cur application/octet-stream
.dcr application/x-director
.deploy application/octet-stream
.der application/x-x509-ca-cert
.dib image/bmp
.dir application/x-director
.disco text/xml
.djv Image/x.djvu
.djvu Image/x.djvu
.dll application/x-msdownload
.dlm text/dlm
.dnl application/x-msdownload
.doc application/msword
.dot application/msword
.dsp application/octet-stream
.dtd text/xml
.dvi application/x-dvi
.dwf drawing/x-dwf
.dwg image/x-dwg
.dwp application/octet-stream
.dxr application/x-director
.eml message/rfc822
.emz application/octet-stream
.eot application/octet-stream
.eps application/postscript
.etx text/x-setext
.evy application/envoy
.exe application/octet-stream
.fdf application/vnd.fdf
.fif application/fractals
.fla application/octet-stream
.flr x-world/x-vrml
.flv application/x-shockwave-flash
.gif image/gif
.gtar application/x-gtar
.gz application/x-gzip
.h text/plain
.hdf application/x-hdf
.hdml text/x-hdml
.hhc application/x-oleobject
.hhk application/octet-stream
.hhp application/octet-stream
.hlp application/winhlp
.hqx application/mac-binhex40
.hta application/hta
.htc text/x-component
.htm text/html
.html text/html
.htt text/webviewhtml
.hxt text/html
.ico image/x-icon
.ics application/octet-stream
.ief image/ief
.iii application/x-iphone
.inf application/octet-stream
.ins application/x-internet-signup
.ips application/x-ipscript
.ipx application/x-ipix
.isp application/x-internet-signup
.ivr i-world/i-vrml
.jad text/vnd.sun.j2me.app-descriptor
.jar application/java-archive
.java application/octet-stream
.jck application/liquidmotion
.jcz application/liquidmotion
.jfif image/pjpeg
.jpb application/octet-stream
.jpe image/jpeg
.jpeg image/jpeg
.jpg image/jpeg
.js application/x-javascript
.kml Application/vnd.google-earth.kml+xml
.kmz Application/vnd.google-earth.kmz
.latex application/x-latex
.lit application/x-ms-reader
.lpk application/octet-stream
.lsf video/x-la-asf
.lsx video/x-la-asf
.lzh application/octet-stream
.m13 application/x-msmediaview
.m14 application/x-msmediaview
.m1v video/mpeg
.m3u audio/x-mpegurl
.man application/x-troff-man
.manifest application/x-ms-manifest
.map text/plain
.mdb application/x-msaccess
.mdp application/octet-stream
.me application/x-troff-me
.mht message/rfc822
.mhtml message/rfc822
.mid audio/mid
.midi audio/mid
.mix application/octet-stream
.mmf application/x-smaf
.mno text/xml
.mny application/x-msmoney
.mov video/quicktime
.movie video/x-sgi-movie
.mp2 video/mpeg
.mp3 audio/mpeg
.mp4 Video/mp4
.mp4 video/mp4
.mpa video/mpeg
.mpe video/mpeg
.mpeg video/mpeg
.mpg video/mpeg
.mpp application/vnd.ms-project
.mpv2 video/mpeg
.ms application/x-troff-ms
.msi application/octet-stream
.mts Application/metastream
.mvb application/x-msmediaview
.mw2 Image/x.mw2
.mwx Image/x.mwx
.nc application/x-netcdf
.nsc video/x-ms-asf
.nws message/rfc822
.ocx application/octet-stream
.oda application/oda
.ods application/oleobject
.odt application/vnd.oasis.opendocument.text
.p10 application/pkcs10
.p12 application/x-pkcs12
.p7b application/x-pkcs7-certificates
.p7c application/pkcs7-mime
.p7m application/pkcs7-mime
.p7r application/x-pkcs7-certreqresp
.p7s application/pkcs7-signature
.pbm image/x-portable-bitmap
.pcx application/octet-stream
.pcz application/octet-stream
.pdf application/pdf
.pfb application/octet-stream
.pfm application/octet-stream
.pfx application/x-pkcs12
.pgm image/x-portable-graymap
.pko application/vnd.ms-pki.pko
.pma application/x-perfmon
.pmc application/x-perfmon
.pml application/x-perfmon
.pmr application/x-perfmon
.pmw application/x-perfmon
.png image/png
.pnm image/x-portable-anymap
.pnz image/png
.pot application/vnd.ms-powerpoint
.ppm image/x-portable-pixmap
.pps application/vnd.ms-powerpoint
.ppt application/vnd.ms-powerpoint
.prf application/pics-rules
.prm application/octet-stream
.prx application/octet-stream
.ps application/postscript
.psd application/octet-stream
.psm application/octet-stream
.psp application/octet-stream
.pub application/x-mspublisher
.qt video/quicktime
.qtl application/x-quicktimeplayer
.qxd application/octet-stream
.ra audio/x-pn-realaudio
.ram audio/x-pn-realaudio
.rar application/octet-stream
.ras image/x-cmu-raster
.rba 3DVista Audio
.rdf application/xml
.rf image/vnd.rn-realflash
.rgb image/x-rgb
.rm application/vnd.rn-realmedia
.rmi audio/mid
.rmvb application/vnd.rn-realmedia-vbr
.roff application/x-troff
.rpm audio/x-pn-realaudio-plugin
.rtf application/rtf
.rtx text/richtext
.scd application/x-msschedule
.sct text/scriptlet
.sea application/octet-stream
.setpay application/set-payment-initiation
.setreg application/set-registration-initiation
.sgml text/sgml
.sh application/x-sh
.shar application/x-shar
.sit application/x-stuffit
.ski 3DVista SKI
.skz 3DVista SKZ
.smd audio/x-smd
.smi application/octet-stream
.smx audio/x-smd
.smz audio/x-smd
.snd audio/basic
.snp application/octet-stream
.spc application/x-pkcs7-certificates
.spl application/futuresplash
.src application/x-wais-source
.ssm application/streamingmedia
.sst application/vnd.ms-pki.certstore
.stl application/vnd.ms-pki.stl
.sv4cpio application/x-sv4cpio
.sv4crc application/x-sv4crc
.svg image/svg+xml
.svg2 image/svg+xml
.svgz image/svg+xml
.swf application/x-shockwave-flash
.t application/x-troff
.tar application/x-tar
.tcl application/x-tcl
.tex application/x-tex
.texi application/x-texinfo
.texinfo application/x-texinfo
.tgz application/x-compressed
.thn application/octet-stream
.tif image/tiff
.tiff image/tiff
.toc application/octet-stream
.tr application/x-troff
.trm application/x-msterminal
.tsv text/tab-separated-values
.ttf application/octet-stream
.txt text/plain
.u32 application/octet-stream
.uls text/iuls
.ustar application/x-ustar
.utx Text/xml
.vbs text/vbscript
.vcf text/x-vcard
.vcs text/plain
.vdx application/vnd.visio
.vml text/xml
.vsd application/vnd.visio
.vss application/vnd.visio
.vst application/vnd.visio
.vsw application/vnd.visio
.vsx application/vnd.visio
.vtx application/vnd.visio
.wav audio/wav
.wax audio/x-ms-wax
.wbmp image/vnd.wap.wbmp
.wcm application/vnd.ms-works
.wdb application/vnd.ms-works
.wks application/vnd.ms-works
.wm video/x-ms-wm
.wma audio/x-ms-wma
.wmd application/x-ms-wmd
.wmf application/x-msmetafile
.wml text/vnd.wap.wml
.wmlc application/vnd.wap.wmlc
.wmls text/vnd.wap.wmlscript
.wmlsc application/vnd.wap.wmlscriptc
.wmp video/x-ms-wmp
.wmv video/x-ms-wmv
.wmx video/x-ms-wmx
.wmz application/x-ms-wmz
.wps application/vnd.ms-works
.wri application/x-mswrite
.wrl x-world/x-vrml
.wrz x-world/x-vrml
.wsdl text/xml
.wvx video/x-ms-wvx
.x application/directx
.xaf x-world/x-vrml
.xbm image/x-xbitmap
.xdr text/plain
.xla application/vnd.ms-excel
.xlc application/vnd.ms-excel
.xlm application/vnd.ms-excel
.xls application/vnd.ms-excel
.xlt application/vnd.ms-excel
.xlw application/vnd.ms-excel
.xml text/xml
.xof x-world/x-vrml
.xpm image/x-xpixmap
.xsd text/xml
.xsf text/xml
.xsl text/xml
.xslt text/xml
.xsn application/octet-stream
.xwd image/x-xwindowdump
.z application/x-compress
.zip application/x-zip-compressed


// 프로그램을 구현 하면서 Object들을 하나의 구조에 모아서 사용해야 할 경우에 
// C# 에서는 List, ArrayList 등이 존재하는데 이들의 차이점이 무엇인지 알고 싶어졌다.
// 그래서 각각의 특성을 정리 해 보고자 한다.

1. What  are C# Collection Classes
    - The C# Collection classes are a set of classes designed specifically for grouping togather objects and performing tasks on them.
    - C# 의 컬렉션 클래스는 각 오브젝트들을 모으고 그 모아놓은 오브젝트들을 사용하기 위한 클래스들을 모아놓은 것이다.

2. Creating C# List Collection - List<T> and ArrayList
    - C#의 array와 비슷한 속성을 가지고 있으나 이 두 클래스들의 중요한 특징은 저장되어 있는 오브젝트들의 수에 따라 (자동적으로)커질수도 작아질 수도 있다는 것이다.(Array는 한번 생성하면 크기가 고정되어 있어 늘릴 수 없다.)
    - 저장되어 있는 namespace 도 다르다.(List<T>는 System.Collections.Generic ArrayList는 Sysyem.Collections)
    - 생성하는 방법은 간단히 new 함수를 사용하면 된다. 이때 다른점은 List는 가지고 있을 오브젝트의 type을 명시 해 주어야 한다는  것이다.

3. Other Caracteristics
    - 상황 : 일정 크기의 배열을 선언한 다음에 인덱스를 사용해서 오브젝트를 넣으려고 한다.
        - List<T> 와 ArrayList는 실패
        - 일반적인 Array 는 성공

4. 결론
    - 별다른 차이점이 없다.
    
Introduction

Text files are easy way to store data in either comma separated values or separated by new line. While working with many application usually we come across situations where we need to read and write data from / into text files. This article describes different approach of reading and writing data into the text files.

Essentials

In order to work with reading and writing data from / into text file, you will have to use System.IO namespace. You need to specify the path of the file to read from and write data into as Physical path on your hard driver. If you know the physical path of your file you want to read or write, you can specify as follows

string fileNameWithPath = @"E:\Csharp\temp\withsinglelinecode.txt";

If you do not know or not sure the path of the file from the drive or you want to create the text file in your applications sub folders, you can get the physical file path by using Server.MapPath method and passing the location of the file from your root directory of the application.

string fileNameWithPath = Server.MapPath("temp/withsinglelinecode1.txt");

In order to create a new line into the text file, you can use System.Environment.NewLine or "\r\n", to place a tab space you can use "\t". Reading data from text file and showing on the web page, will not automatically convert \r\n to new line, you will have to replace these characters with the <br /> as shown below.

litText.Text = contents.Replace("\r\n", "<br />");

Here litText is the Literal control I have placed in my .aspx page to show the contents of the file.

Reading and Writing with Single line of code


To simply write and read all contents of any any text file, you can use following one line code.

C# Code

 string data = "This is the first line . \r\n" 
    + "This is the second line. next two line space \r\n\r\n"
    + "\t This comes after a tab space";

// writing content into a text file with a single line of 
codeFile.WriteAllText(fileNameWithPath, data);

// reading content from a textfile with single line of codestring 
contents = File.ReadAllText(fileNameWithPath);

// Format the data with new line so that on the web page it appears in the new line
litText.Text = contents.Replace("\r\n", "< br />");

In the above code snippet, File.WriteAllText method accepts following parameters

  1. fileNameWithPath - physical location of the file with its name
  2. data - contents to write into the text file

File.ReadAllText method accepts following parameters

  1. fileNameWithPath - physical location of the file with its name

In the remaining lines, I have replaced the new line characters with the "<br />" so that it appears as next line in my web page.

Appending contents into a File and Reading data one by one

C# Code

 // Append data into the text file
using (StreamWriter writer = File.AppendText(fileNameWithPath))
{
    // writer.Write method will simply append the contents into the text // file without creating a new line
    writer.Write("NEW LINE ADDED without Creating a line line. ");
    writer.Write("This line will not appear into new line. ");
    
    // writer.WriteLine method append the contents into the text file 
    // and add a new line so that next appended contents appear in new line
    writer.WriteLine("Appended into above line but next appended contents will appear into a new line. ");
    writer.Write("This should appear in the next line. ");
}

// Read data from text file
using (StreamReader reader = File.OpenText(fileNameWithPath))
{
    // reads a single line of contents
    contents = reader.ReadLine();

    // reads complete contents of the the file
    contents += reader.ReadToEnd();
}

litText.Text = contents

In the above code snippets, I am using StreamWriter to append the contents into the file. File.AppendText method accepts physical location of the file with its name and returns StreamWriter, that can be used to append contents into the text file. This can be done using Write method or WriteLine method.

  1. writer.Write() - method accepts contents to append and simply append the contents at the end of the file.
  2. writer.WriteLine() - method accepts contents to append and add a new line after appending contents so that next appended contents appears in the new line.
Reading and Writing using FileStream

C# Code

// using File Stream
fileNameWithPath = Server.MapPath("temp/filestream.txt");

// writing contents using FileStream
using (FileStream stream = File.Open(fileNameWithPath, FileMode.OpenOrCreate))
{
     // writing data
     byte[] info = new UTF8Encoding(true).GetBytes(data);
     stream.Write(info, 0, info.Length);
}
// Reading contents using FileStream
using (FileStream stream = File.OpenRead(fileNameWithPath))
{
     // reading data
     StringBuilder strb = new StringBuilder();
     byte[] b = new byte[stream.Length];
     UTF8Encoding temp = new UTF8Encoding(true);

     while (stream.Read(b, 0, b.Length) > 0)
     {
           strb.Append(temp.GetString(b)); 
     }

     // write the contents of the file now
     Response.Write("Using FileStream 
" + strb.ToString() + "
"); }

FileStream object gives you extra control over how you want to read or write data from / into a file. This also let you specify the mode of the file to access like in Append mode, or Create mode or only Read mode. Also you can specify Type of access you want to have as third parameter of the File.Open() method.

FileStream buffers input and output for better performance. In order to use FileStream for reading and writing, you will need to use System.Text namespace as encoding related objects like UTF8Encoding contains in this namespace.

For detailed explanations FileStream, please visit MSDN.

'Framework' 카테고리의 다른 글

LINQ 자료  (2) 2009.10.09
C# Collection Classes (부제:List 와 ArrayList 의 차이 )  (0) 2009.10.06
[펌]Mircrosoft Office 2007 Groove 사용 방법  (0) 2009.09.02
XML 특수문자 처리  (0) 2009.08.11
.NET Naming Rule Guidelines  (0) 2009.07.02
아래는 FullTextSqlQuery를 이용하고,
검색 범위를 지정하여 해당 범위안에 있는 아이템을 검색하는 소스이다.


string strQuery = string.Empty;
string strkeyword = "Microsoft";

ServerContext context = ServerContext.Current;
FullTextSqlQuery kQuery = new FullTextSqlQuery(context);

strQuery = "SELECT Title, HitHighlightedSummary, Write, ContentClass, Department, IsDocument, Path, Author, Size, SiteTItle FROM Scope() WHERE \"scope\" = 'Search' AND FREETEXT(defaultproperties, '" + strkeyword + "')";
    //Search는 중앙 관리에서 생성한 검색 범위명
    
kQuery.QueryText = strQuery;
kQuery.ResultTypes = ResultType.RelevantResults;
kQuery.StartRow = 0;
kQuery.RowLimit = 50;
kQuery.EnableStemming = true;
kQuery.TrimDuplicates = true;
kQuery.HighlightedSentenceCount = 3;
kQuery.Culture = CultureInfo.CurrentCulture;
kQuery.KeywordInclusion = KeywordInclusion.AllKeywords;
kQuery.Timeout = 60000;
kQuery.AuthenticationType = QueryAuthenticationType.NtAuthenticatedQuery;

ResultTableCollection resultTbls = kQuery.Execute();
if ((int)ResultType.RelevantResults != 0)
{
       ResultTable tblResult = resultTbls[ResultType.RelevantResults];

       DataTable resultDataTable = new DataTable();
       resultDataTable.Load(tblResult, LoadOption.OverwriteChanges);

       gvSearchResult.DataSource = resultDataTable;
       gvSearchResult.DataBind();
}

특정 문서 라이브러리에 대한 리스트 아이템에 대해서 검색하도록 검색 범위를 지정한 후,
해당 문서 라이브러리에 여러 문서를 업로드한다. (이때, 많은 문서를 손쉽게 업로드 하기 위해 원도우 탐색기를 이용하여 업로드 하였다.)
그리고, 크로링 작업을 완료 한 후, 검색을 해보았다.
그런데 이때 위 소스에 Author 부분에 아이템의 작성자가 아닌, 이상한 값들이 있는것을 발견!!!

테스트 해 본 결과!!
원도우 탐색기를 열때, 기존의 인증(시스템 계정)이 물려 있었다.
쿠키 및 캐시 때문인가 싶어 지우고도 다시 해보았으나, 처음에 물려있던 인증창이 한번 물리면 안풀린다
(어떻게 해야 풀리는지 찾지는 못함. 단, 어느정도 시간 지나면 풀림)

우선 일차적인 문제는 시스템 계정 인증 문제였으나,
왜 Author에 시스템 계정으로 나오지 않고, 다른 이름이 나오는가 의문을 갖게 되어 찾아본 결과..

시스템 계정 인증으로 Office를 업로드 한 문서를 검색할 경우, 
해당 Office 문서의 만든이로 Author에 등록되어 나온다는 것을 알았다.
그리고 Office 문서가 아닌 이미지와 같은 파일은 시스템 계정으로 나온다.

인증 문제로 인해 다시 삽질을 하지 말자는 바램으로 정리 해보았다.
  • 로그 파서 설치 및 구성
  1. 로그 파서는 IIS 로그 파일에 저장된 정보를 이용하여 원하는 수치를 뽑을 수 있습니다.
  2. 서버에서 Log Parser를 수행하면, 서버 부하를 줄 수 있기 때문에 클라이언트 PC에 Log Parser 2.2를 다운로드(http://go.microsoft.com/fwlink/?LinkId=139171)받아 설치합니다.
  3. 명령 프롬프트에서 쉽게 로그 파서를 사용하려면 시스템 환경 변수 path에 C:\Program Files\Log Parser 2.2 를 추가합니다.
  4. Log Parser 2.2 API도 제공됩니다.

    (기본 설치 시 C:\Program Files\Log Parser 2.2폴더 아래 LogParser.chm 파일이 있을 것입니다.)

 

  • 운영 현황 분석을 위한 기본 설정
  1. Log Parser를 이용한 운영 현황 분석을 위해서는 웹 프런트 앤드 각 웹 서버의 인터넷 정보 서비스 관리에서 IIS 로깅 사용 기능이 활성화하며, W3C 확장 로그 파일 형식 선택합니다.

  2. 운영 현황을 조사하기 위해서는 최소한 아래와 같은 필드가 선택되어 있어야 합니다. (속성을 클릭 후, 고급 탭을 보시면 됩니다.)

     

필드명

컬럼명

날짜 (Date)

date

시간 (Time)

time

클라이언트 IP 주소

c-ip

사용자 이름

cs-username

메소드

cs-method

URI 스템

cs-uri-stem

프로토콜 상태

sc-status

프로토콜 하위 상태

sc-substatus

보낸 바이트 수

sc-bytes

받은 바이트 수

cs-bytes

걸린 시간

time-taken

사용자 에이전트

cs-user agent

 

  • IIS 로그 파일 수집
  1. 웹 프런트 앤드 각 웹 서버의 IIS 로그 파일을 수집하여 클라이언트 PC의 특정 폴더에 저장 합니다. (웹사이트가 여러 개 일 경우, 해당 사이트 IIS 로그만 추출하면 됨)
  2. IIS 로그 파일은 해당 웹 사이트의 로깅 속성을 보시면 로그 파일 디렉터리가 표시되어 있습니다. (아래 그림으로는 C:\WINDOWS\system32\LogFiles\W3CVC797352875 폴더입니다.)

  3. 여러 대의 웹 서버 IIS 로그를 수집할 경우, 파일이 중복되므로 로그 파일명 앞에 해당 서버명을 붙여 수집하는 것이 좋습니다.

 

  • Log Parser명령을 이용한 운영 현황 분석
  1. 명령 프롬프트를 실행하여 Log Parser명령어 입력하면 아래와 같은 설명이 나타납니다.

  • 명령어 사용법 : (자세한 건 API 및 Log Parser Helper 참고)

    LogParser [-i:<input_format>][-o:<output_format>]<SQL query> | file:<query_filename>[?param1=value1+…][<input_format_options>][<output_format_options>][-q[:ON|OFF]][-e:<max_errors>][-iw[:ON|OFF]][-stats[:ON|OFF]][-saveDefaults][-queryInfo]

  • -i : 로그 파일 포맷 타입으로 IIS log Files, Window Event Log, XML, CSV, TSV, W3C Text File 등을 지원합니다.
  • -o : 쿼리 현황 디스플레이 포맷 타입으로 CMD 창에서 확인할 수 있으며, Text File, SQL 데이터 베이스, 차트형 이미지 등으로 출력도 가능합니다.
  • -q : 디폴트로는 OFF 이며, Query 실행 마지막 부분까지 한번에 보여지며, 통계 자료도 표시되지 않습니다.
  • CMD창에 직접 입력이 아닌, txt 파일에 query 입력한 후 해당 파일을 읽어와 현황 쿼리도 가능합니다. (SQL Query문이 길 경우 추천)
  • 명령어 마지막에 ">user.txt"와 같이 > 입력 후, 파일명을 입력하면 로그저장 폴더 안에 user.txt 파일에 쿼리 조건 현황이 저장되어 있습니다.
  1. 명령 프롬프트 창에서 IIS 로그 파일을 저장한 폴더로 이동합니다.
  2. Log Parser Query 명령어를 입력하여 해당 조건에 대한 운영 현황을 알 수 있습니다..
  3. 몇 가지 Log Parser Query 실행 및 운영 현황 결과 (IISW3C 로그 파일)
  • Counting Users (시스템의 유니크 사용자)
    • 쿼리 대상 기간의 로그 파일에서 유니크한 방문자를 구합니다.

      Logparser –i:IISW3C –o:CSV "select DISTINCT TO_UPPERCASE(cs-username) AS USERNAME from *.log group by cs-username" –q >users.csv (엑셀 파일에 저장)

    • 주의 사항으로 대소문자 구분하지 않습니다. 정확한 현황을 위해 위 쿼리문과 같이 Log Parser 함수(TO_UPPERCASE, 기타 함수는 API 참고)를 이용하여,

  • Load balancing
    • 1차 가공을 위한 데이터로 사용자 별 서버 로드 밸런스를 분석합니다.

    • 요일, 서버 별 사용자 접속 카운터 수를 구합니다.

    • 사용자 별 로그 카운터 수를 구합니다.

  • User type distribution
    • 쿼리 대상 기간의 로그 파일에서 시스템을 가장 많이 쓰는 Top 3 사용자를 구합니다.

    • HTTP 상태가 401인 상태가 포함되어 있으므로, 필터하여 분석합니다.

  • Request (RPS) distribution over time (시간에 따른 RPS 분포)
    • RPS(Request Per Second)는 초당 서버에 전달되는 사용자 요청수의 합으로써 사이징 시에 기본 고려 값이 되며, RPS를 시간대에 맞추어 뿌려보면 시간대 별로 서버 부하가 어떻게 달라지는지 알 수 있습니다.
    • RPS 분석 쿼리는 복잡하기 때문에 텍스트 파일(load.txt)로 작성하여 Log Parser 파라미터에 전달합니다.

select EXTRACT_FILENAME(LogFilename),LogRow,

date, time, cs-method, cs-uri-stem, cs-username, c-ip, cs(User-Agent), cs-host, sc-status, sc-substatus, sc-bytes, cs-bytes, time-taken,

add(

add(

mul(3600,to_int(to_string(to_localtime(to_timestamp(date,time)),'hh'))),

mul(60,to_int(to_string(to_localtime(to_timestamp(date,time)),'mm')))

),

to_int(to_string(to_localtime(to_timestamp(date,time)),'ss'))

) as secs,

 

to_int(to_string(to_localtime(to_timestamp(date,time)),'yy')) as yy,

to_int(to_string(to_localtime(to_timestamp(date,time)),'MM')) as mo,

to_int(to_string(to_localtime(to_timestamp(date,time)),'dd')) as dd,

 

to_int(to_string(to_localtime(to_timestamp(date,time)),'hh')) as hh,

to_int(to_string(to_localtime(to_timestamp(date,time)),'mm')) as mi,

to_int(to_string(to_localtime(to_timestamp(date,time)),'ss')) as ss,

 

to_lowercase(EXTRACT_PATH(cs-uri-stem)) as fpath,

to_lowercase(EXTRACT_FILENAME(cs-uri-stem)) as fname,

to_lowercase(EXTRACT_EXTENSION(cs-uri-stem)) as fext

from *.log

where sc-status<>401

1차 가공한 데이터 파일인 bigo.csv 파일을 만듭니다.

  • bigo.csv 파일로부터 분당 분포 값과 초당 분포 값을 뽑습니다.

    초 단위

    분 단위

  • 위 쿼리 실행 파일에서 시간 별 평균과 분/초당 최대값을 뽑습니다.

    시간 별 평균

    분당 최대값

    초당 최대값

  • 사용자의 요청으로 시작한 RPS 값만 구하고자 할 때 .gif, .png, .bmp, .js, .css and .axd 파일과 같은 정적인 경우를 Where절을 이용하여 Filter 하면 됩니다.

    예시로, where sc-status<>401 and fext<>'gif' and fext<>'png' and fext<>'bmp' and fext<>'js' and fext<>'css' and fext<>'axd' 와 같이 필터 해주면 됩니다.

     

  • Distinct users over time (시간대별 유니크 사용자 수)
    • 1차 가공한 데이터를 userdist.csv 파일로 만듭니다.

    • 시간대에 따른 사용자 정보

    • 시 단위별 유니크 사용자 수

    • 분 단위별에 따른 유니크 사용자 수

  • User agent distinction (사용자 클라이언트 활용 비율 분석)
    • 사용자 클라이언트 활용도가 높은 Agent가 무엇인지 분석

    • 위 데이터는 Browser Requests 에 외부 파라미터 정보까지 포함되어 있어, EXTRACT_TOKEN 함수를 이용하여 브라우저 정보만 분석합니다.

  • Browser usage (브라우저 사용 패턴 분석)
    • 1차 가공한 데이터를 ie.csv 파일로 만듭니다.

      (Mozilla 이며, HTTP 상태가 401이 아닌 정보만 가져옵니다.)

    • 파일 형태에 따른 분석(어떤 파일이 많이 접속 되었는지 분서 가능)

    • aspx 파일 중에 어떤 파일에 접속이 많았는지 분석

    • 어떤 ASMX 웹 서비스 호출이 많았는지 분석

  • Office client Web Service usage (자주 쓰이는 웹 서비스 분석)
    •  
  • Slow pages (사용자 반응 시간대 분석)
    • Default.aspx 페이지에 대한 반응 시간을 5분 간격으로 분석

    • Default.aspx 페이지에 대한 접속 카운트 수를 5분 간격으로 분석

    • Default.aspx 페이지에 대한 반응 시간이 느린 시간대를 5분 간격으로 분석

      (걸린 시간 4초 이상)

  • Importing logs into SQL Server
    • Log 정보를 SQL Server 특정 Table에 저장합니다.

    • 해당 쿼리 조건의 Log 정보만 SQL에 저장합니다.

    • 쿼리 조건을 저장한 파일을 로드하여 수행 가능합니다.

[sql.txt(쿼리 저장 파일)]

select EXTRACT_FILENAME(LogFilename),LogRow, date, time, cs-method, cs-uri-stem, cs-username, c-ip, cs(User-Agent), cs-host, sc-status, sc-substatus, sc-bytes, cs-bytes, time-taken,    

add(

add(

mul(3600,to_int(to_string(to_localtime(to_timestamp(date,time)),'hh'))),

mul(60,to_int(to_string(to_localtime(to_timestamp(date,time)),'mm')))

),

to_int(to_string(to_localtime(to_timestamp(date,time)),'ss'))

) as secs,

 

to_int(to_string(to_localtime(to_timestamp(date,time)),'yy')) as yy,

to_int(to_string(to_localtime(to_timestamp(date,time)),'MM')) as mo,

to_int(to_string(to_localtime(to_timestamp(date,time)),'dd')) as dd,

 

to_int(to_string(to_localtime(to_timestamp(date,time)),'hh')) as hh,

to_int(to_string(to_localtime(to_timestamp(date,time)),'mm')) as mi,

to_int(to_string(to_localtime(to_timestamp(date,time)),'ss')) as ss,

 

to_lowercase(EXTRACT_PATH(cs-uri-stem)) as fpath,

to_lowercase(EXTRACT_FILENAME(cs-uri-stem)) as fname,

to_lowercase(EXTRACT_EXTENSION(cs-uri-stem)) as fext

 

into ShpLogTable

from *.log

 

where sc-status<>401

 

 


I've been spending a lot of time with Office and syncronizing properties with WSS document libraries I thought I would share. There are a few sources out there like the WSS FAQ section on Office Interaction but I thought I would try to get into some more detail here as there are some dos and donts and gotchas along the way.

Concept

When you upload a document through one of several ways, properties from the document will transfer to SharePoint fields automagically. This assumes you've actually setup the fields in WSS (only the Title property is created by default). There are four ways to upload a document to a SharePoint document library where this works:

  1. Copy and paste the document into Explorer View
  2. Drag and drop a document via a mapped drive (Windows XP only) or through your Network Places folder
  3. Save the document directly from Word/PPT/Excel into a WSS document library.
  4. Upload multiple files via the Office 2003 capability

The last two options require Office 2003 (although you can save from Office 2000 and XP it doesn't always work properly as WebDAV is a little kludgy)

Uploading the document through the "Upload Document" option on the toolbar for the document library is a Upload->Set Properties excercise. In other words, you have to upload the document (by picking it via the Browse button) then set the properties. When you select a file from your system to upload, the properties are not automatically set (although I feel they should be so hopefully we'll see this in a future version or service pack). Using the "Upload Multiple Files" gets around this problem, but again requires an Office 2003 client.

Built-in Properties

Word, Office, Powerpoint and Excel (and maybe OneNote and the other "core" products) have a set of default file properties. You can set these programatically (through COM automation) or via the File | Properties menu. These properties are:

  • Subject
  • Author
  • Manager
  • Company
  • Category
  • Keywords
  • Comments
  • Hyperlink base

These properties do not transfer to a SharePoint document library (again, I think a failing of WSS and should be fixed).

Note: There is something deep in the central administration screens that talk about mapping Office DAV properties so I'm still looking into how this works and maybe to overcome this problem.

Custom Properties - Microsoft

In addition to the built-in properties, Microsoft creates by default a series of custom properties. These are accessible via the File | Properties menu on the Custom tab. By default they're all blank but you can choose to set any of them. These are named:

  • Checked By
  • Client
  • Date completed
  • Department
  • Destination
  • Disposition
  • Division
  • Document Number
  • Editor
  • Forward To
  • Group
  • Language
  • Mailstop
  • Matter
  • Office
  • Owner
  • Project
  • Publisher
  • Purpose
  • Received from
  • Recorded by
  • Recorded date
  • Reference
  • Source
  • Status
  • Telephone number
  • Typist

Creating a field in the WSS document library with the same name as these will result in a transfer (if the property is set in the document and you use one of the four ways to upload the document). Note that once you create a field, it has an internal name (like Status) but you can change it after the fact. It will always have that internal name and if that name maps to a property, it stays that way no matter what name you change it to.

Custom Properties - Yours

Just like the default custom properties that Microsoft creates, there's no stopping you from adding any custom property. Just type in the name in the File | Properties custom tab and click Add. This will add a new property like "Creator" or something. You'll still have to set this but if you do, it will transfer to WSS (again if you create the field in the document library to match).

Transfering

As mentioned in this blog, properties set in Office documents will transfer to a WSS document library as long as two conditions are met:

  1. The property is set in the document itself as a text custom property
  2. The field is created in the WSS document library as a text field

Custom Properties - Lookups

One of the nice things about having meta-data for your documents in WSS is that you can control the properties and lookup values. Lookup tables are great for this but there's a problem with properties and transfering using a lookup. It doesn't work. Say you have a field called "Status" (one of the default custom properties) and set it "Draft" in the document. Status is a lookup into another SharePoint list you created where the user can set the value. When you transfer the document to WSS, the property doesn't get set.

However if your "Status" field in WSS is a choice field with the values you want AND you have the document property set to something that matches, the transfer works correctly. WSS doesn't care you have a custom property called "Status" in your document with a value of "Fixed" but the choices in WSS are only "Draft" and "Final". It will gleefully set the value to "Fixed" but when you edit the properties, since WSS can't find "Fixed" in the list of choices, it'll revert back to nothing (or the default value if this is a mandatory field).

So basically, if you want to have a picklist for your lookups and syncronize those values from Office -> WSS and back again:

  1. Ensure the WSS field type is "Choice" with a set of values (multi-choice through checkboxes does not syncronize)
  2. Ensure the property in Office is a text value and matches one of the choices in the WSS document library

Value Types

Office documents let you create 4 different value types for custom properties. Synchronziation (and the field type) in WSS must be text only and the type in the office document must be the same so store all custom properties in your office documents as Text fields in order to ensure synchronization.

Syncronization

As for keeping things in sync, if you set the property in WSS it will transfer to the document so when you open it and look at the File | Properties | Custom tab they'll be updated. If you set it in the document it will tranfser using one of the four methods described above. If you save a single document directly into the document library, it will clear out the file property and ask you for the value.

Summary

In conclusion, it's a powerful feature to synchronize (and populate) SharePoint document libraries with properties from Office documents. Imagine if you had a document library with all kinds of views using meta-data and you had a massive amount of documents with these properties set. A simple drag-n-drop operation into your document library and now all your views are ready to go. Even with issues around syncronization and non-existent built-in properties, it's a useful feature to leverage in your solutions.

Other References

WSS FAQ - Interaction with Office
WSS FAQ - Syncronization Issues with Certain Properties


Mircrosoft Office 2007 Groove란?

Groove는 현재의 인터넷에 가장 최적화된 업무공유 프로그램이 아닐까 싶습니다. 물론 다른 프로그램들도 많습니다만, 굳이 Groove를 최고의 프로그램으로 판단하는 것은 바로 "협업"에 이유가 있습니다.

협업이라.. 다소 생소하겠죠.. 우리가 이해하기 쉬운 말로 하면, 컨소시엄 혹은 프로젝트 팀 업무라고 할 수 있겠습니다.

즉, 하나의 프로젝트를 수행하는 수행원이 여러명일때, 그들의 각 업무를 어떻게 조화를 시켜야 할까요? 무조건 절차를 따지다 보면, 작업의 소요시간을 넘기는 경우가 빈번하게 발생됩니다. 그렇기에 프로젝트 매니저가 생겨나고, 그는 절차와 시간, 방법, 예상결과를 토데로 프로젝트를 수행해 나갑니다. 하지만, 각 수행원에 의해 실시간으로 수정 및 업데이트되는 데이터를 처리하기엔 너무나 힘이 듭니다.

이럴 때, 매니저는 Groove를 이용할 수 있습니다. 수행원간의 커뮤니케이션을 도와주고, 서로의 업무가 겹치지 않게 그리고, 많은 데이터들로 혼란스럽지 않게 도와 줍니다.

 

협업가능 프로그램

저는 평소업무에서도 컨소시엄 혹은 협업을 자주 하게 됩니다. 지금까지의 업무 공유는 메일이나, 메신져, 파일공유등을 이용해왔습니다. 프로그램의 선택방법은 우선 페이퍼와 같은 경우 이메일을 보내고, 파일용량이 크면 웹하드를 사용해야 합니다. 하지만 웹하드는 상대가 업로드를 해야 하고, 나는 업로드가 완료되었는지 확인 해야 하며 또한 다운로드를 해줘야 합니다. 그래서 메신저를 사용하곤 하는데, 채팅을 할 수 있다는 것은 좋지만, 파일전송은 오류가 많아서 별루 반갑지 않습니다. 또한 전송하는 파일을 어떠한 기준에 따라 정렬하기란 더욱 어렵구요.

 

Groove 프로그램 특징

그럴땐, Groove가 많은 부분들을 해결해 줍니다. 바로 다음과 같은 장점 때문입니다.

1. 고용량 파일

용량이 제법 큰 파일도 전송하는데에 무리는 없습니다. 물론 전송속도는 네트워크의 상태에 따라 다르겠지만, 파일 전송중에 끊기는 일은 타 프로그램에 비해 적습니다.

2. 실시간 파일 전송

파일이 전송되는 것을 누군가가 실행해야 하는 방식이 아닌, 프로그램이 알아서 업로드와 다운로드를 해줍니다.

3. 채팅

수행원간의 커뮤니티를 위해 채팅이 지원됩니다.

4. 웹 기능

게시판, 사진 게시판, 일정, 메모장등의 기능을 공유하여 사용할 수 있습니다.

5. 폴더 공유

수행원의 컴퓨터 간에 물리적으로 같은 네트워크에 있지 않아도 공유가 가능합니다.

6. 최신 파일 공유

하나의 파일을 여러명이 수정하고 수정후 공유하는 방식이기에, 항상 최신 파일을 보관, 배포 할 수 있습니다.

 

Groove 프로그램의 단점

1. 권한 설정

아직은 수행원에게 다양한 권한을 부여할 수는 없습니다. 현재는 3가지의 권한만 부여됩니다. 참석자, 관리자, 방문자입니다.

2. 초대방식

이메일을 이용하여 초대해야 하며, 피초대자가 능동적으로 검색하기가 힘들다는 것입니다.

3. History

수정과 업데이트로 인한 백업이 되지 않기에, 수해원 중 누군가가 실수를 범할 경우 곤란할 수 있습니다.

4. 어플리케이션

사용자와의 어플리케이션이 아직은 좀더 손봐야 하지 않을까 싶습니다. 게시판, 사진등.. 우리가 기존에 자주 사용하는 댓글과 본문에 사진 첨부등은 아직 좀 힘듭니다.

아쉬운 점은 많겠지만, 차차 낳아질 것이라고 기대해 봅니다.

 

Groove 설치

Groove는 현재 Ms Office중에 하나의 프로그램으로 되어 있습니다. 즉, Microsoft Office 2007을 설치하면 자동으로 추가 설치 할 수 있습니다. 하지만, office가 어려 버전이 있으므로, 확인을 해봐야 합니다.

위에서 보듯이, Groove는 Ultimate나 Enterprise로 설치해야만 합니다.

물론, 평가판을 이용할 순 있습니다. 60일 트라이얼이며, 설치해보진 않아서 확인해 보진 않았지만, 기능적 제한이 없으며, 60일 이후에도 계속 사용할 수 있다고 합니다.

다운로드는

http://trial.trymicrosoftoffice.com/trialkorea/product.aspx?sku=3082923&culture=ko-KR

에서 가능합니다.

언어 지원은

http://www.microsoft.com/downloads/details.aspx?familyid=a114d1c4-d42b-408a-b223-82a12e5e4a15&displaylang=ko

에서 다운 받으실 수 있습니다.

참고로, 제가 Ms Office 2003을 사용하면서 Groove 2007 평가판을 설치하려고 했으나, 원인 모를 오류로 설치가 되지 않았습니다.

평가판의 설치 혹은 Office 2007의 설치방법은 MS 웹사이트 혹은 매뉴얼을 참고하시길 바라며, 생략하겠습니다.

 

프로그램을 설치한 뒤 처음 실행을 하면 계정을 추가마법사가 실행됩니다.

새 계정 추가로 선택한뒤, 자신의 이메일 계정과 간단한 개인정보를 입력하시면 됩니다.

이때, 패스워드는 Groove를 실행할때마다 묻게 되는 비밀번호이니 꼭 기억해 두어야 합니다.

설치를 할 때 혹은 실행을 할 때 패스워드를 저장하기를 이용하면 되지만, 다른 PC에 계정 사용하기를 할 경우 다시 필요로 합니다.

 

Groove사용방법

작업영역 추가

작업영역추가 방법은 다양하며, 간단한 방법은 실행창의 바탕에 마우스 오른쪽의 클릭으로 손쉽게 생성 할 수 있습니다.

생성된 작업영역창은 아래와 같습니다.

 

구성원 추가

구성원을 추가하여 파일공유가 가능하도록 하는 방법을 알아 보겠습니다.

구성원 추가방법은 여러방법이 있습니다. 그중에서 역시나 가장 간편한 마우스 오른쪽기능을 사용해 보겠습니다.

실행창에서 해당 작업영역을 마우스 오른쪽으로 클릭-> 초대방법 -> Outlook를 선택합니다.

초대설정은 역할(권한)설정입니다. 관리자와 참석자 방문자에 따라 기능 추가/삭제 파일 쓰기권한등이 부여됩니다.

저는 참석자로 선택하여 확인을 클릭하겠습니다.

이제 이렇게 초대파일이 첨부되어 메일 창이 떴습니다. 받는 사람에 참석자의 이메일 주소를 입력한 뒤 보내기를 실행합니다.

상대는 이메일을 받고 첨부파일을 더블클릭하여 실행하면 Groove에서 해당 작업영역이 추가되고, 작업영역 다운로드(동기화)가 실행되며, 다운이 완료되면 구성원으로써 이용가능합니다.

 

파일전송에 의한 초대

이메일 계정이 없으시거나, 메신저와 같은 프로그램을 이용해서 초대파일을 보내고 싶으실때에는 이메일에 첨부된 파일과 같은 초대파일을 생성한뒤 구성원에게 보내 주시면 됩니다.

실행창의 해당 작업영역을 마우스 오른쪽으로 클릭 -> 초대를 파일로 저장을 선택합니다.

초대 파일 저장 창에서는 파일이 저장되는 위치를 확인해 두어야 합니다.

그리고, 역할도 설정을 해 두셔야 합니다.

 

이제 저장된 파일을 메신저와 같은 파일을 이용해서 구성원에게 전송하시면 됩니다.

해당 파일을 받은 구성원은 역시, 더블클릭으로 해당 파일을 실행하면 작업영역의 공유가 시작됩니다.

 

파일 공유방법

파일 공유 방법은 매우 쉽습니다.

작업영역창에서 파일 탭으로 이동한 뒤 '파일추가'를 실행하거나, 탐색기에서 파일을 작업영역창으로 드레그 하시면 복사가 됩니다.

다른 기능들은 이와 유사하거나, 게시판과 같은 어플리케이션이므로 생략합니다.

 

다른 컴퓨터에서 계정 사용하기

자신의 계정을 다른 컴퓨터에서 사용하는 기능이 있습니다. 즉, 회사에서 쓰는 작업영역 그대로 집에서 사용할 수 있습니다.

파일과 기타 기능들을 모두 똑 같은 환경에서 사용할 수 있습니다.

실행창의 파일 -> 다른 컴퓨터에서 계정 사용을 클릭합니다.

아래의 다른 컴퓨터에 복사할 계정 파일 저장을 클릭하신뒤 해당 파일을 다른컴퓨터로 이동시킨 후 실행하시면 됩니다.


약 1800만 화소 CMOS 센서의 고화질과 약 8 프레임/초의 고속 연사를 양립. 프로기에 강요하는 고화질·고성능의 디지털 일안 리프 카메라“캐논 EOS 7 D”


캐논은, 프로기에 필적하는 기능이나 성능에 가세해 다양한 사용법을 실현한 하이 아마츄어 전용의 디지털 일안 리프 카메라“캐논 EOS 7 D”를 10 월상순에 발매합니다.

EOS 7D
(EF-S15-85mm F3.5-5.6 IS USM 장착시)
EOS 7 D(배면)
무선 파일 송신기
WFT-E5B
  • 캐논 EOS 7D 보디
    오픈 가격 (발매일:2009연 10 월상순)
  • 캐논 EOS 7D EF-S15-85 IS U 렌즈 킷
    오픈 가격 (발매일:2009연 10 월상순)
  • 캐논 EOS 7D EF-S18-200 IS 렌즈 킷
    오픈 가격 (발매일:2009연 10 월상순)
  • 캐논 무선 파일 송신기 WFT-E5B
    가격(세금 별도) 9만 5,000엔 (발매일:2009연 11 월상순)
이 건에 관한 문의처
캐논 고객 상담 센터
TEL:050-555-90002
  • 해외로부터 이용의 경우, 또는 050에서는 글자 만IP전화 번호를 이용하실 수 없는 경우는, TEL 043-211-9556 에 문의해 주세요.

신제품“EOS 7 D”는, 「타협이 없는 스펙의 실현과 시각·청각·촉각에 호소하는 진짜 질감」을 컨셉에, 화질이나 기능, 다양한 쓰기를 고집하는 하이 아마츄어를 메인 타겟으로 개발한 최첨단의 디지털 일안 리프 카메라입니다.새롭게 개발한 약 1800만 화소의 CMOS 센서(APS-C사이즈)와 고성능 영상 엔진을 2개 장비한 듀얼 DIGIC 4의 채용에 의해, 높은 해상감과 풍부한 계조성을 갖추면서, 최고 약 8 팽이/초※1의 고속 연사와 약 94매※2의 연속 촬영을 실현하고 있습니다.또, 상용 설정할 수 있는 ISO 감도※3를 ISO100?6400까지 확보해 노이즈의 적은 아름다운 화질을 실현하는 것과 동시에, 확장 설정에 ISO12800를 준비하고 있어, 어두운 장소에서의 촬영에 위력을 발휘합니다.


게다가 정확한 구도나 핀트 맞댐이 가능한 시야율 약 100%·시야각 29.4о·배율 약 1.0배의 고성능인 광학 파인더나, 중앙에 고정밀도의 듀얼 크로스 센서를 탑재한 「올 크로스 19점 AF」, AF정보와 색정보를 이용해서 안정된 노출을 실현하는 「iFCL(intelligent Focus Color Luminas) 측광」 등, 고도이고 충실한 기본 성능을 장비하고 있습니다.

 

동영상 촬영기능 「EOS 무비」는, 풀 HD(1,920×1,080 화소·30/25/24프레임/초)를 시작으로 하는 다채로운 기록화질에 대응하는 것과 동시에, 조임치·셔터 속도·ISO 감도를 임의로 설정할 수 있는 메뉴얼 노출로의 촬영도 가능하게 하고 있습니다.또, 약 15만회의 작동 내구를 자랑하는 신개발의 셔터나, 수평 방향과 전후방향의 기울기를 검출하는 「듀얼 악시스 전자 수준기」, 액정과 커버 유리의 사이에 특수 수지를 충전해 공기층을 없애는 것으로 보기 쉬움을 추구한, 강화유리 채용의 3.0형 크리아뷰 액정 II 등 수많은 최신 기술을 탑재하고 있습니다.디자인에 대해서는, 면의 곡율을 연속적으로 변화시킨, 흐르는 곡면을 활용한 「초유체 디자인」을 채용하는 것으로, 최첨단의 일안레플렉스 카메라에 어울리는 품격을 연출하고 있습니다.

 

덧붙여“EOS 7 D”에 맞추고, 촬영한 화상을 무선/유선 LAN를 통해 서버나 PC에 전송 할 수 있는 것 외에 복수의 카메라의 셔터 동작을 무선으로 연동시키는 「카메라 연동 촬영기능」 등 다채로운 신기능을 탑재한“무선 파일 송신기 WFT-E5B”를 발매합니다.

  • ※1 CIPA 기준에 의한다.
  • ※2 캐논 시험 기준 메모리 카드 사용.JPEG·라지/파인.
  • ※3 ISO 감도는 추천 노광 지수.

【디지털 일안 리프 카메라의 시장동향】

작년의 디지털 일안 리프 카메라의 출하 대수(전세계)는, 연말에 성장이 둔화했지만, 연간을 통한 시장은 대전년대비 약24%증가의 약 930만대에 이르렀습니다.2009년은 세계경제의 정체의 장기화가 염려되지만, 디지털 일안 리프 카메라 시장은, 대전년대비로 약 4%증가의 약 970만대로 견조한 성장의 계속이 전망되고 있습니다.(캐논 조사해)

【개발의 배경】

캐논은 미들 클래스의 디지털 일안 리프 카메라로서 35 mm풀 사이즈 CMOS 센서에 의한 고화질이 특징의 「EOS 5D Mark II」(2008년 11월 발매)과 본격적으로 사진을 시작하려고 하는 유저나 하이 아마츄어에게 최적인 스탠다드 모델 「EOS 50 D」(2008년 9월 발매)의 2 라인을 투입해, 시장의 성장에 공헌해 왔습니다.


이번 발표하는“EOS 7 D”는, 스포츠나 스냅, 동물, 탈 것의 촬영 등 움직임이 있는 피사체의 촬영으로부터 정물이나 풍경 촬영에 이르기까지 폭넓은 용도를 향해서 개발한 제품입니다.제품 개발에 임해서는, 특별한 프로젝트를 조직 하고, 사진 표현에 조건이나 정열을 가지는 유저를 조사·연구해, 사진을 찍는 기쁨과 카메라를 가지는 기쁨을 동시에 만족시키는 제품 만들기를 추구했습니다.독자 개발의 CMOS 센서나 고성능 영상 엔진등에 의해서 뛰어난 스펙을 실현하는 것과 동시에, 보디 디자인이나 홀드감, 셔터음등도 중시한 상질의 카메라로 완성하고 있습니다.


캐논에서는, 신제품“EOS 7 D”를 「EOS 5D Mark II」라고와 같이 열심인 사진 애호가를 타겟으로서 시장 투입해, 하이 아마츄어 전용의 라인 업을 3 라인에 강화합니다.이것에 의해 엔트리로부터 프로까지의 라인 업에 새로운 두께를 더해 확장해 심화 계속 하는 일안레플렉스 카메라의 유저 요구에 대응해 갈 것입니다.

 

원문 : http://cweb.canon.jp/newsrelease/2009-09/pr-eos7d.html

 

 

 

캐논, 파인더 시야율 100%의 APS-C최상위기종 「EOS 7 D」

~19점 크로스 AF센서, 8 팽이/초기록, 풀 HD동영상에 대응


 캐논은, 약 8 팽이/초의 연사 성능을 가지는 디지털 일안 리프 카메라 「EOS 7 D」를 10 월상순에 발매한다.가격은 open price.

상품명 가격 매장 예상 가격 발매 시기
EOS 7 D보디 open price 19만엔 전후 10월상순
EOS 7D EF-S18-200 IS렌즈 킷 26만엔 전후
EOS 7D EF-S15-85 ISU 렌즈 킷 27만엔 전후

 

EOS 7D.장착 렌즈는 모두 EF-S 17-85mm F4-5.6 IS USM

 「EOS 50 D」(2008년 9월 발매)의 상위에 위치하는 미들 클래스 모델.「타협이 없는 스펙의 실현과 시각·청각·촉각에 호소하는 진짜 질감」을 컨셉의 하나로 하고 있어, 예를 들면 파인더 시야율은, APS-C사이즈 상당한 CMOS 센서를 탑재하는 EOS DIGITAL로서 첫 100%를 실현하고 있다.더해 AF센서, 연사 성능, AE시스템등을 EOS 50 D나 EOS Kiss X3로부터 브러시 올라가는 것과 동시에, 풀 HD동영상 기록에도 대응했다.

 

 덧붙여 EF-S15-85 ISU 렌즈 킷에 부속되는 신렌즈 「EF-S 15-85mm F3.5-5.6 IS USM」나, EOS 7 D에 장착 가능한 무선 송신기 「WFT-E5」에 대해서는, 각각 별페이지로 소개하고 싶다.

본체만으로 8 팽이/초의 연사가 가능

 촬상 소자는 APS-C사이즈 상당한 유효 1,800만 화소 CMOS 센서.클래스 최다의 화소수가 된다.RAW의 기록화 소수는 5,184×3,456 피크셀.2,592×1,728 피크셀의 S-RAW에 가세해 3,888×2,592 피크셀의 M-RAW의 기록도 가능.sRAW1, sRAW2라고 하는 호칭은 아니게 되었다.

 

 상용 감도는 ISO100~6400.감도 확장으로 최고 ISO12800로의 촬영도 행할 수 있다.유효 촬영 화각은 렌즈 표기 촛점거리의 1.6배 상당하고, EF마운트 및 EF-S마운트에 대응.

 

 화상 처리 엔진 「DIGIC4」를 2개 탑재.EOS-1 D/1 Ds계와 같은 듀얼 엔진의 생각을 계승하는 것으로, 화상 처리에 여유가 태어나 데이터 기입등의 동작이 고속화한다고 한다.덧붙여서 EOS 50 D는 DIGIC4를 1개 탑재하는 싱글 구성이었다.

 

 고속 연사 성능도 향상했다.본체만으로 약 8 팽이/초의 촬영이 가능.또, CF슬롯은 UDMA에 대응한다.JPEG 라지/파인으로의 연속 기록 매수는, 최대 약 126 팽이가 되고 있다.또, 기입중에 슬롯 커버를 열어도, 기입 조작을 중단하지 않는 특징을 가지고 있다.

 

 액정 모니터는 3형약 92만 닷.수치상은 EOS 50 D와 동등하지만, 액정 파넬과 보호 패널의 사이에 광학 탄성체를 충전해, 진공 상태에 가공하는 「솔리드 구조」를 채용하는 것으로, 외광하에서의 보기 쉬움이 향상했다고 한다.액정 파넬과 보호 커버동안에 고미가 들어오는 문제도 해소했다.종래의 크리아뷰 액정과 같이, 반사·더러워져·상처 방지의 멀티 코트도 베풀고 있다.

 

 또, EOS 5D Mark II등이 채용하는 외광 센서도 탑재.재생 화상 확인시는, 최초로 검지한 환경에서 밝기를 고정하도록(듯이) 개선했다고 한다.

19점 모든 것을 크로스 센서화

 측거 점수는 EOS 50 D의 9점에서 19점에 증가했다.센서의 배치는 능형으로, 모든 AF센서에 크로스 센서를 채용한다.한층 더 중앙에는, 기울기 십자에 F2.8 광속 대응, 종횡 십자에 F5.6 광속 대응의 듀얼 크로스 센서를 탑재.측거 에리어 선택 모드로서 19점으로부터 임의의 1점을 선택하는 「1점 AF」, 지정한 존내에서 피사체를 자동 검출하는 「존 AF」, 카메라가 19점으로부터 자동적으로 선택하는 「자동 선택」의 3개로부터 선택할 수 있게 되었다.이 중 존 AF모드는, 5 분할된 존으로부터 임의의 존을 선택 가능.자동 선택 모드에서는, AI서보 AF시에 피사체 추종 표시도 가능이라고 한다.측거점의 선택은 전자 다이얼, 또는 멀티 콘트롤러로 행할 수 있다.

 

 또, EOS-1 D/1 Ds계의 「AF프레임 영역 확대」를 계승.선택한 측거점을 피사체가 빗나가도, 상하 좌우의 측거점이 자동으로 어시스트 한다.그 외 , 사용하지 않는 AF프레임을 표시시키지 않게 되어 있다.더해 AI서보 AF가 「AI서보 AF II」에 진화.소지로의 매크로 촬영에서도 효과가 있다고 한다.

 

 AF관련에서는 그 외 , AF시작 버튼에 선택 AF프레임, AE락 버튼에 등록 AF프레임을 할당하는(역도 가능) 일이 「AF개시 위치 선택」으로 가능하게 되어, AF프레임 선택의 스텝을 간략화할 수 있게 되었다.또한 등록 AF프레임에의 이동은 멀티 콘트롤러 중앙 밀기에서도 가능.

 

 또 하나의 신기능 「AF제어 전환 등록」에서는, 추출 버튼 및 렌즈 버튼에, 측거 에리어(스포트, 임의, 영역 확대, 존, 19점 전자동), AI서보 추종 민감도, AI서보시의 측거점선택 특성, AI서보1/2팽이눈 이후라고 하는 동작의 어느쪽이든을 할당.움직이는 피사체의 성질에 맞추고, 씬 마다의 사용구분이 가능하다.

시야율 100%·배율 1배의 파인더를 장비

 파인더 시야율은 EOS 50 D의 약 95%로부터 퍼져, 약 100%를 실현했다.배율도 약 0.95배로부터 약 1.0배에 확대.EF렌즈 사용시, 육안과 거의 같은 크기로 피사체를 볼 수 있다고 한다.또, 투과형 액정 디바이스를 이용한 「인텔리전트 뷰 파인더」를 채용.EOS DIGITAL로서 첫 기능으로, 「AF프레임 표시」, 「시야 우치오모테시」, 「구라두 라인 표시」, 「스포트 측광 표시」, 「파인더 내수 준기 표시」를 교체된다.그 대신 focusing 스크린의 교환을 할 수 없게 되었다.

 

 측광 시스템에도 손이 더해지고 있다.세로 2층 구조의 63 분할 듀얼 층 측광 센서를 신개발 해, AF정보, 색정보를 이용하는 「iFCL(intelligent Focus Color Luminas) 측광 시스템」을 짜넣었다.19점의 AF프레임에 대해, 어느 AF프레임으로 피사체를 파악해도, 그 측광 에리어에 적절히 웨이트를 걸칠 수 있다.구도에 관련되지 않고, 주피사체와 배경의 노출 밸런스를 최적화한다고 한다.측광 모드로서는, 종래와 같이 「평가 측광」, 「부분 측광」, 「스포트 측광」, 「중앙부 중점 평균 측광」으로부터 선택이 가능하다.

 

 라이브뷰는 얼굴 우선 라이브 모드에 대응.독자적인 전자처막셔터 방식에 의한 정음 모드도 EOS 50 D와 같이 이용할 수 있다.카메라내에서의 렌즈 주변 광량·자동 보정도 EOS 50 D에 계속해 탑재한다.

24 p나 60 p로의 HD동영상 기록이 가능

 EOS 50 D에 없었던 동영상 기록에도 대응한다.EOS DIGITAL에서는, EOS 5D Mark II, EOS Kiss X3에 뒤잇는 탑재가 된다.계속 「EOS 무비」의 명칭으로 소구 한다고 한다.압축 방식은 종래와 같게 MPEG-4 AVC.음성은 리니어 PCM.

 

 기록 해상도 및 frame rate는, 1,920×1,080 피크셀이 30 p·25 p·24p.1,280×720 피크셀이 60 p·50p.640×480 피크셀이 60 p·50 p가 되고 있다.24 p, 25 p, 60 p, 50 p는 지금까지의 EOS 무비에 없었던 frame rate.또, 음성 샘플링 주파수가 44.1 kHz에서 48 kHz가 되었다.

 

 또, 파무웨압데이트 후의 EOS 5D Mark II와 같이, 동영상 기록으로의 메뉴얼 노출에도 대응.내장 마이크로의 간이 녹음(단청의)에 가세해 3.5 mm스테레오 미니 잭 경유로의 외부 마이크 접속도 이용할 수 있다.카메라내에서의 동영상의 컷 편집도 가능하게 되었다.

 

 또, EOS DIGITAL 첫 전자 수준기를 탑재.수평 및 전후의 2 축으로 대응해, 라이브뷰 촬영시, 파인더 촬영시, 동영상 기록시의 모두로 이용할 수 있다.촬영 대기중에도 표시가 가능하고, 삼각 설정시에 기울기를 보는 기준이 된다.

내장 strobe에 송신기 기능을 탑재

 내장 strobe에 송신기 기능을 내포 했던 것도 토픽.지금까지 EOS DIGITAL에서는, 외부 크리프온스트로보에 의한 무선 라이팅을 행할 때, 마스터가 되는 스피드 라이트 송신기 「ST-E2」나, 크리프온스트로보 상급기의 「스피드 라이트 580EX II」를 홋트슈에 장착할 필요가 있었다.EOS 7 D에서는, 내장 strobe가 송신기 기능을 가져, 본체만으로의 다등 제어가 가능하게 되었다.

 

 내장 strobe의 조사각은 15 mm(35 mm판 환산으로 24 mm상당)를 커버.지금까지는 17 mm였다.킷 렌즈 EF-S 15-85mm F3.5-5.6 IS USM의 광각단으로, 케라레무사히 strobe 촬영을 할 수 있다.

 

 셔터 유닛도 새로워졌다.물리적인 접촉면이 없는 비접촉식 로터리 마그넷을 채용.EOS 5D Mark II의 셔터 유닛으로부터 기본 구조를 계승하는 것과 동시에, EOS-1 D/1 Ds계와 동등의 파트를 채용해, 15만회의 셔터 내구 회수를 클리어 한다.또한 EOS 50 D는 10만회가 되고 있다.

 

 덧붙여서, 셔터음에 대해서도 재검토를 도모해, 「금속적이고 절도 있는, 날카로운 릴리즈음을 실현했다」라고 하고 있다.셔터 유닛의 부재나 밀러 바운드 억제 기구를 재검토하는 것과 동시에, 모터나 기어의 구동음도 차음.불쾌한 소리를 차단했다고 한다.또, 슬롯 커버에도 완충재를 넣는 것으로, 개폐시의 소리를 억제하고 있다.

지금까지 없는 다채로운 커스터마이즈 성능

 버튼 레이아웃은 EOS 50 D로부터 크게 변화했다.우선, 메인 스위치를 배면 좌상에 배치.EOS 50 D에서는 서브 전자 다이얼 좌하에 있어, 서브 전자 다이얼의 락 기구와 일체가 되고 있었다.락 기구 그 자체는 계속해 이용할 수 있다.또 EOS 7 D에서는, 파인더우횡에 라이브뷰/동영상 촬영 전용 스윗치를 탑재.EOS 5D Mark II나 EOS Kiss X3에는 없는 조작계로, 레버로 라이브뷰와 동영상 촬영을 바꾸어 두고 버튼을 누르는 것으로 각각의 표시 또는 기록이 시작된다.

 

 보디 하부에 있던 메뉴계 버튼은, 액정 모니터 좌측으로 옮겼다.EOS 30 D시대로 돌아온 것이 된다.동시에 많은 버튼이 사이즈 업.한층 더 조작계 버튼을 중심으로 외장면으로부터 내미게 하는 것으로, 장갑을 한 채로의 촬영이 용이하게 되었다고 한다.버튼의 대형화에 따라, 아이콘을 버튼에 직접 인쇄했던 것도 특징.종래는 버튼의 우상 등에 프린트 하고 있었다.

 

 파인더왼쪽으로 원터치 RAW+JPEG 버튼을 신탑재.누를 때마다 JPEG→JPEG+RAW, RAW→JPEG+RAW등으로 바꾼다.EOS DIGITAL에서는 첫 기능이 된다.한층 더 셔터 버튼 부근에는, 새롭게 「멀티 펑션(M-Fn) 버튼」을 탑재했다.FE락, 원터치 RAW+JPEG, 듀얼 악시스 전자 수준기의 어느쪽이든을 할당해 두어 순간으로 전환할 수 있다.

 

 배면 액정 모니터로의 퀵 설정 화면(정보 표시)에 대해서도, 파인더왼쪽으로 전용 버튼을 마련하는 것으로 쓰기에 배려.EOS 50 D는 마르치콘토라의 중앙 밀기였다.또, 퀵 설정 화면으로부터도 들어갈 수 있는 「C.FN IV:조작·그 외 조작 부재에의 기능 할당 변경」에서는, 셔터, AF-ON, AE락, 좁혀, 렌즈, 멀티 펑션, 세트의 각 버튼이나, 전자 다이얼, 서브 전자 다이얼, 멀티 콘트롤러라고 한 대부분의 조작 부재에 다른 기능을 할당같게 되었다.이것도 EOS DIGITAL로서 첫 기능으로, 종래보다 대담한 조작 커스터마이즈가 가능하게 된다.

방진방적보디를 채용

 배터리에는, EOS 5D Mark II와 같은 리튬 이온 충전지의 LP-E6를 채용.CIPA 규격 준거의 촬영 가능 팽이수는, 파인더 촬영시에 약 800 팽이(상온), 약 750 팽이(저온).라이브뷰 촬영시에 약 220 팽이(상온), 약 210 팽이(저온).

 

 전용의 밧테리그리프 「BG-E7」(2만 1,000엔)도 발매한다.LP-E6를 2개 장비 가능하고, 배터리 매거진에 의해 단 3 전지의 사용도 행할 수 있다.본체에 세로 위치 조작용의 AE락, 측거점선택, AF시작 버튼등을 탑재.방진방적구조가 되고 있다.

 

 보디는 방진방적구조로, 외장은 마그네슘 합금제.전지실, 메모리 카드 슬롯 커버 개폐부, 각종 조작 버튼 주위 등에 실링 부품을 채용.외장 커버의 고정밀도 단차 맞댐 구조나, 그립 러버의 밀착 구조등에 의해, EOS 50 D를 넘는 방진방적성능을 실현했다고 한다.

 

 모드 다이얼에는 아르미링판이나 금속 볼을 채용.서브 전자 다이얼도 알루미늄제가 되어 있다.그립도 신설계가 되어, 힘이 걸리는 부분의 러버를 두껍게 하는 등, 그립감의 향상이나 손의 피로를 경감했다고 한다.종래의 캐논 중급기는 러버후가 균등이었다.

 

 본체 사이즈는 148.2×73.5×110.7 mm(폭×깊이×높이).중량은 약 820g.EOS 50 D와 거의 같은 본체 사이즈면서, EOS 5D Mark II( 약 810 g)와 거의 동등의 본체 중량이 되어 있다.

 

 부속 어플리케이션은, 「Digital Photo Professional 3.7」, 「ZoomBrowser EX 6.4.1」, 「EOS Utility 2.7」, 「Picture Style Editor 1.6」 등.이 중 EOS Utility에서는, PC로부터의 리모트라이브뷰 촬영시에 외부 strobe의 조 광이 가능하게 되는 것 외에 밀러 업 촬영에 대응한다.또 ZoomBrowser EX는 60 fps로 기록한 동영상의 재생이 가능.

 

주된 사양
  EOS 7D EOS 50D EOS Kiss X3
발매 시기 2009년
10월상순
2008연
9월 27일
2009연
4월 24일
실세(예상) 가격
※보디만
19만엔 전후 12만엔 전후 9만엔 전후
촬상 소자 방식 CMOS 이미지 센서
사이즈 22.3×14.9 mm
유효 화소수 약 1,800만 약 1,510만
유효 촬영 화각 약 1.6배
최고 감도(확장 설정) ISO12800
센서 클리닝
영상 엔진 DIGIC4×2 DIGIC4×1
라이브뷰
EOS 무비 최대 해상도 1,920×1080 1,920×1080
frame rate
(최대 해상도시)
30p/25p/24p 20fps
파인더 시야율 약 100% 약 95%
배율 약 1.0배 약 0.95배 약 0.87배
아이포인트 약 22 mm 약 19mm
위상차이 AF측거점 19점 9점
셔터 최고속 1/8,000초 1/4,000초
연속 촬영 속도 약 8 팽이/초 약 6.3 팽이/초 약 3.4 팽이/초
액정 모니터 사이즈 3형
닷수 약 92만 닷
본체 사이즈 148.2mm 145.5mm 128.8mm
깊이 73.5mm 73.5mm 61.9mm
높이 110.7mm 107.8mm 97.5mm
중량(본체만) 약 820 g 약 730 g 약 480g

 

'Misc' 카테고리의 다른 글

Getting Word 2003 and 2007 to play nicely with each other  (0) 2010.03.15
Music Program  (0) 2009.11.13
로또 최다 1등 당첨번호는 '1' '37'  (0) 2009.08.07
소녀 시대 사진  (2) 2009.07.14
에비앙의 "롤러스케이트 타는 아기들"  (0) 2009.07.12

u      연봉 및 월급에서의 혜택

 

앞 장에서 기술사 교육비 지원 혜택과 기술사 취득 후 매월 지급하는 수당에 대해 설명을 하였다. 이렇듯 대부분의 기업에서는 기술사를 취득하게 되면 주는 매월 수당과 인사고가가 명시되어 있다. 보통 기업을 보면 20만원 이상을 주고 있는데 이는 연 240만원이고 10년이면 2,400만원이다. 자동차를 한 대 할부로 구입하면 지출되는 돈과 비슷하니, 차 한대가 공짜로 굴러 떨어지는 것과 유사하다고 할 수 있겠다.

 

앞에서 언급한 회사 중 매월 나오는 수당이 가장 많은 곳이 35만원 이였다. 필자가 알고 있기로는 가장 많이 줄려고 하는 회사가 50만원이라고 한다. 그런데 이곳은 불행히도 아직 기술사를 보유하지 못했다. 하여튼 없는 곳은 빼고 가장 많이 받고 있는 회사를 기준으로 월 35만원 수당을 계산하면 연 수령액이 420만원이니 10년이면 4,200만원이다. 지방의 아파트 한 채 값이다. 서울에서 아파트에 거주해도 집 평수를 넓혀 가거나 주택 구입자금 대출을 받아도 원금과 이자 상환 금액은 얼추 충당하게 된다. 또는 물 좋고, 경치 좋은 곳의 전원주택 구입비 정도 지불 할 수 있다. 그렇게 따지면 기술사 자격증의 가치는 조금 과장해서 아파트 한 채 값이라고 해도 될 성 싶다.

 

결국 기술사의 가치는 실제 받게 되는 돈만 하더라도 차 한대나 아파트 한 채 만 큼의 가치가 있다고 말할 수 있다. 하지만 IT를 본업으로 하지 않는 관공서, 은행, 대기업 등에서는 지원 혜택이 적은 곳도 있다.  

 

 

¤      기능사, 기술자, 기술사의 노임 단가 차이 

 

기술사의 경우에는 임금에서도 많은 혜택이 주어지는데, 일반적으로 20년 이상의 경험을 가진 특급 기술자 보다 많은 임금을 받고 있는 것으로 조사되었다. 물론 기업마다 여러 종류의 혜택을 기술사에게 주고 있지만, 아래의 <1-12> 2008년도 소프트웨어사업의 노임단가를 보면 기술사들이 가장 많은 돈을 받고 있으며, 기술사들이 특급 기술자보다 많은 보수를 받고 있음을 알 수 있다. 이러한 사례는 일반적인 통계이지만, 좀 더 자신의 가치를 높이고자 할 경우에 기술사는 가장 좋은 대안 중의 하나임을 증명한다고 할 수 있다.

  

 

소프트웨어산업진흥법시행령 제16(S/W기술자의 등급별 노임단가)의 규정에 의한 소프트웨어사업의 대가기준에 적용할 소프트웨어기술자 등급별 일 노임 단가를 통계법 제23조에 의거 다음과 같이 공표합니다.  

 

<1-12> 2008년도 소프트웨어사업의 노임단가


SW
기술자 등급별 노임단가
(
단위:,,%)

2007
조사인원

노임단가

전년대비

2006년도

2007년도

증가액

증가율

기술사

141

277,516

290,938

13,422

4.84

특급기술자

4,076

267,495

273,664

6,169

2.31

고급기술자

3,531

206,698

215,166

8,468

4.10

중급기술자

3,969

165,245

174,432

9,187

5.56

초급기술자

5,470

130,898

136,290

5,392

4.12

고급기능사

102

108,268

112,910

4,642

4.29

중급기능사

269

95,632

99,834

4,202

4.39

초급기능사

105

71,102

75,128

4,026

5.66

<시행일> 2008 1 1부터

 

출처: 한국 소프트웨어 산업협회 (http://www.sw.or.kr) 

 

 

 

u      1 기업이 가능한 기술사 (기술사 사무소 설립 및 활동)

 

기술사는 기술사법 및 엔지니어링 기술 진흥법에 의해서 기술사 사무소를 설립하여 엔지니어링 활동 및 엔지니어링 사업을 할 수 있도록 규정되어 있다. 이러한 엔지니어링 주체를 기술사 사무소라고 할 수 있는데, 기술사 사무소의 등록은 의사나 변리사와 같이 면허의 성격이 있다고 할 수 있다. 또한 기술사법이 개정되면 종합 기술사 사무소를 설립하여 활동할 수 있는데, 여기에는 아주 특별한 의미가 있다. 예를 들어 인천 신공항 구축 프로젝트의 경우 공항에 대한 건설, 토목 등의 하드웨어 기술과 그것을 운영하는 정보시스템의 소프트웨어가 필요한데, 종합 기술사 사무소는 이러한 종합적인 프로젝트를 수행할 수 있는 권리와 의무를 갖게 되는 것으로 향후 기술사의 역할은 더욱 증대될 것으로 예상되고 있다

 

¤      국가기술자격 등급종목별 활용 현황 (출처: 한국산업인력공단)

 

자격종목

사업법상 활용 현황

정보관리

기술사

(0601)

-「엔지니어링기술진흥법」에 의한 엔지니어링활동 주체 기술인력

-「전기통신공사업법」에 의한 전기통신공사업 등록을 위한 기술인력

전자계산

조직응용

기술사

(0620)

-「엔지니어링기술진흥법」에 의한 엔지니어링활동 주체 기술인력

-「전기통신공사업법」에 의한 전기통신공사업 등록을 위한 기술인력

 

 

¤      기술사 사무소 설립 및 활동 (출처: 한국기술사회자료)

 

. 기술사 사무소의 정의

 

기술사법 제3조의 규정에 의한 기술사의 직무를 수행코자 기술사법 제6조 제1항의 규정에 의하여 개업을 하고자 하는 기술사가 과학기술부장관에게 등록하는 제도로서 기술사 직무수행의 권리와 그에 따른 의무를 부여하는 것이다.

 

. 기술사 사무소의 직무범위(업무범위)

 

기술사법 제3조의 규정에 의한 기술사 직무를 수행하고, 다른 법에 특별한 규정이 없는 한 엔지니어링 기술 진흥법 제2조의 규정에 의한  "엔지니어링활동""엔지니어링사업"을 각각 영위할 수 있다.

 

1)기술사의 직무는 과학 기술에 관한 전문적 응용능력을 필요로 하는 사항에 대하여 계획, 연구,  분석,설계, 조사,시험,시공,감리,평가,진단,사업관리,기술판단,기술중재 또는 이에 관한 기술자문과 기술 지도이다.

 

2)엔지니어링 활동은  과학 기술의 지식을 응용하여 사업 및 시설물에 관한 기획, 타당성 조사,분석, 설계, 구매,조달, 시험, 감리, 시운전, 평가, 자문 및 지도 등의 활동과 그 활동에 대한 사업 관리를 의미한다.

 

3)엔지니어링 사업은 엔지니어링 활동 주체에게 엔지니어링 활동을 발주하는 것을 의미한다.

 

.기술사 사무소 등록의 의미

 

일정한 사실 또는 법률 관계를 행정청이나 당해 행정사무를 위임 또는 위탁 받은 기관에 비치되어 있는 등록 장부에 기재하는 행위이며  기술사 사무소 등록은  의사 및 변리사 사무소 등록과 같이 면허의 성질이 있는 행위이다.

 

. 기술사 사무소 등록 행위의 성립 요건

 

등록행위가 유효하게 성립하기 위해서는 먼저 그 주체내용, 형식, 절차의 모든 점에서 관계법령이 규정하고 있는 요건에 적합하여야 할뿐 아니라, 공익에 적합하여야 한다.

 

1)주체에 관한 요건 : 등록 행위는 정당한 권한을 가진 자의 그 권한의 범위 내에서 정상적인 의사에 의하여 행해져야 한다.

 

2)내용에 관한 요건 : 등록행위는 그 내용에 있어 실현가능하고, 명확한 것이어야 하며 법령과 공익에 적합 하여야 한다.

 

3)절차에 관한 요건 : 법령이 정하는 절차에 따라 행해져야 하고 중요한 사항에 대하여 누락이 없도록 하여야 한다.

 

4)형식에 관한 요건 : 등록행위가 유효하게 성립하기 위해서는 문서 기타법령이 규정하고 있는 형식을 갖추어야 한다.

 

5)등록행위의 외부적 표시 : 등록행위는 외부에 표시되어야만 비로소 유효하게 성립한다.  따라서  등록기관 내부에 있어서 의사결정(등록결재)이나, 등록행위를 표시하는 서류가 작성되었다는 것  만 가지고는 등록행위가 성립되었다고 할 수 있다.

 

. 기술사 사무소 효력 발생 요건

 

등록행위가 그 성립요건이 갖추어졌다고 당연히 그 효력이 발생하는 것은 아니며 등록사실이 등록신청을 한 상대방에게 통지되어야 한다.  따라서 원격지에 있는 자가  등록신청을 한 경우에는 그 통지사실을 입증할 수 있도록 특수우편 등의 방법을 사용하여야 한다.

 

. 기술사 사무소 등록 행위의 효력

 

등록행위가 그 성립요건과 효력발생요건을 구비하면 법령이 정하는 권리와 의무가 발생하게 된다. 따라서 기술사사무소의 등록의 경우 등록한 기술사는 기술사법에 의한 기술사직무 수행 권한과 각종 장부 비치 및 보고. 검사 등 의무를 지게 된다.

 

. 기술사 사무소 개설 등록 방법

 

기술사 사무소의 개설등록자격은 국가기술자격법에 의한 기술사 자격 소지자로 제한되며,  등록신청 방법으로는 기술사 협회에 필요 서류를 제출함으로써 개설할 수 있다.  아래의 표에 간략한 절차를 설명했다.

 

<1-13>  기술사 사무소 등록 방법

구분

절차 및 방법

구비서류

기술사사무소 개설등록신청서 1, 기술사자격증 사본 1, 사무소확보증빙(임대차계약서 사본) 1, 증명사진1

신청절차

신청서 작성 및 구비서류 준비 접수 검토 및 결재 등록증 및 등록수첩 작성 발급

신청방법

기술사회 방문 신청 또는 우편신청

등록 수수료

법적 수수료는 없음

 

 

 

u      5급 공무원(사무관) 응시자격 부여 (필기시험 면제)

 

과거 조선시대에 신분 상승 방법 중에 가장 좋은 것이 장원급제였다. 장원급제를 통해서 관직으로 나가는 것이 학문을 공부하는 사람들의 꿈 이였다. 예전의 장원급제에 해당하는 것이 지금의 사무관(5급 공무원)에 임명되는 것이다. 공무원 9급이나 7급에서 시작해서 내부 진급을 통해 올라가는 방법도 있지만, 사무관(5급 공무원)에 곧 바로 임명되기 위해서는 행정고시, 사법고시, 외무고시, 기술고시 등을 통해 입문할 수 있다.

 

공무원 9급 모집에도 석사와 박사 출신들이 대단위로 몰려서 경쟁이 치열한 가운데 5급 공무원직에 기술사가 진출할 수 있게 된 것은 정말 잘 된 일이다. 2004년부터 행정고시 등을 통하지 않고 기술사 취득 후 곧 바로 사무관에 임명될 수 있는 길이 열린 것이다. 또한 이번 제도는 필기시험이 없고 서류전형(1)을 거쳐, 면접전형만으로 합격여부가 결정이 되기 때문에 아주 파격적인 것이다.

 

시범적으로 몇 년 운영한 다음 지속적으로 제도를 운영할 지는 다음에 결정한다고 한다.  이 제도는 이공계 기피현상 극복과 과학한국 건설을 위한 과학기술전문인력 양성을 위한 국가 시책의 하나이다. 노무현 대통령이 재직하고 있는 참여 정부에서 제 3공화국 시절에 처음 시행했던 제도를 개선시켜서 다시 시행하는 것이다.

 

개인적으로는 이 제도가 이명박 정부에서도 지속되기를 바라지만, 어떻게 진행될지는 2004년부터 현재까지 5급 사무관에 임명된 기술직 공무원들이 기존의 공무원 사회에서 얼만큼 잘해주는가에 달려있다. 

 

2004년 처음 시행된 53명 모집된 5급 공무원(사무관)의 지원 자격은 박사와 기술사가 주요한 요건이었다. 접수 결과 1,531명의 지원자가 있어서 29.11의 높은 경쟁률이 이었는데 이는 9급 공무원과 7급 공무원보다는 낮은 수준이다.

 

최종 합격된 기술사 중에서 필자가 잘 아는 선배 기술사(정보관리기술사)2분이나 되었다. 한 분은 50K.W.P 정보관리기술사(, 40대 초반), 다른 한 분은 69H.H.N 정보관리기술사(, 30대 중반)로 여자분인데 컨설팅 능력이 뛰어나고 차분하게 말씀을 잘하시는 분이다. 특히나 H 기술사()의 경우 2003년 합격한지 1년이 넘은 시점에서 바로 사무관에 합격해서 아주 잘된 경우이다.

 

2005년 시행된 특허청 사무관에 필자의 여자 동기 기술사(71)P.M.J 전자계산조직응용 기술사도 29세에 기술사 합격하고 나서 16개월 만에 5급 공무원(사무관)에 임명되어 대전에서 근무하고 있다.31세에 5급 사무관이 되었으니 향후 장래가 주목된다고 할 수 있다. 더구나 아직 미혼이라 벌써부터 특허청에서 인기라고 한다.

 

 

¤      20055급 공무원 채용 시험 공고 주요 내용 요약

 

[ 과학기술인력 52명 사무관 특별 채용 안내 ]

 

중앙인사위원회는 200562일 이공계 전공 박사나 기술사, 변리사 자격증을 소지한 우수 과학 기술전문인력 52명을 사무관(5)으로 특별 채용할 예정이라고 밝혔다. 지난해에 이어 두 번째로 실시되는 이번 특별채용은 25개 부처 16개 직렬을 대상으로 하며 부처별로는 특허청이 20명으로 가장 많고 이어 국방부와 정보통신부 각 3, 조달청과 기상청, 과학기술부, 산업자원부 각 2, 교육부, 재경부, 통일부, 행자부 등 대부분 부처는 각 1명이다.

 

직렬별 채용인원은 통신기술직이 9명으로 가장 많고 이어 전기직 6, 기계직, 화공직, 건축직 각 5, 전산직, 토목직 각 4, 정보통신기술직, 보건직 각 3,기상직 2, 원자력직, 수산직, 환경직, 농업직, 자원직, 약무직 각 1명 등이다. 서류전형과 면접시험을 통해 선발하게 되며, 서류전형에서는 자격요건, 전공분야, 논문 등을 심사하고, 면접에서는 개별면접 등을 병행해 응시자의 인성, 공직관 및 정책역량 등을 종합평가한다.

 

이번 특별채용시험은 이달 중 시험계획을 공고하고 응시원서를 접수해 9월말까지 서류전형과 면접시험을 거쳐 10월 중 최종합격자를 선발한다. 임용 후에는 12월중 3주간에 걸친 공직적응프로그램을 통해 공직소양, 행정실무 및 정책관리능력 배양 교육 등을 실시할 예정이다. 자세한 사항은 중앙인사위원회 홈페이지(http://www.csc.go.kr) 또는 인재기획과(02-751-1212)를 통해 문의하면 된다. 한편 과학기술 전문인력 사무관 특별채용이 처음 실시된 지난해에는 53명 모집에 1531명이 응시, 291의 높은 경쟁률을 기록한 바 있다.

(그림 깨짐)
<출처:국정브리핑>


 

 

u      개방직 공무원으로 진출 - 정보화 담당관 (4급 서기관), 전문위원 

 

정식 공무원의 제도가 시행되지 전에는 개방직 공무원도 인기가 많았다. 물론 지금도 인기가 높다. 개방직 공무원이라고 하면 일반 기업의 전문인력(전문위원, 전문가) 등에 해당한다. 근무 기간은 2년으로 임명된 후 2년이 지나면 최대 3년간 연장 가능하다.5년이 지나면 다시 동일 분야에 응모하여 다른 응시자와 경쟁해야 한다.

 

행정자치부, 정보통신부 등 각 정부 부처에서는 전문위원이나 정보화 담당관 등의 직위를 수시로 모집하고 있다. 정보화 담당관(4급 서기관 대우)은 경찰청의 총경 또는 경찰서장 급이며, 기업의 IT 분야에서는 CIO 급이다. 정보화 담당관의 역할은 해당 부처의 IT를 총괄하는 역할을 하기 때문에 매우 막중한 자리이다. 각 부처의 전문위원도 해당 부처의 IT 기획이나 사업 추진의 정당성, 방향성 등에 대해 검토하고 연구하게 된다.

 

개방직 공무원의 지위에 있는 동안 국가공무원법 및 계약직공무원 규정에 의한 신분 유지가 가능하며, 업무를 하는 동안 많은Human Network을 가질 수 있어, 근무 기간이 종료한 후 다른 곳으로의 이직이 쉽고, 좀 더 좋은 조건으로 영전할 수 있는 기회가 많다. 다만 근무 기간 동안 대기업이나 대형 SI 회사에서 받은 연봉(인센티브 포함)보다 연봉이 조금 적을 수 있는데, 이는 다른 비 재정적 혜택으로 충분히 상쇄 될 수 있다고 본다.

 

필자의 동기 기술사 중에 한 분인 S 정보관리 기술사도 해양경찰청 정보화 담당관의 공모에 응시하여 당당히 합격하였다. 기술사 합격 후 16개월 만에 일반기업을 상대로 하는 업무를 하다가 해양경찰청의 해당 분야 IT 업무를 총괄하여야 한다고 생각하면 엄청난 자긍심으로 차있게 된다. 하는 일에 보람을 많이 느낄 수 있을 것 같다.

 

공무원의 매력은 무엇일까? 안전한 신분보장과 정년 퇴직 후 일반 기업보다 많은 연금 수령액 등을 말할 수 도 있겠지만, 공무원의 장점은 자신이 열심히 일하면 그 파급 효과가 대 국민 전체로 영향을 줄 수 있다는 것이다. 자신의 노력으로 시스템을 효율적으로 만들면 소요되는 예산이 줄어 국민의 세금 부담을 줄일 수 있고, 좀더 효율적이고 건강한 정부가 만들어 질 수도 있겠다. 일반 개인이나 기업을 상대로 하는 것이 아닌 국민 전체에 대한 서비스 정신과 진취적 기상을 가지고 근무 하여야 공무원 근무가 정말 재미있어 질 것이다.

 

 

u      이직과 전직할 때 좋은 점

 

기술사를 합격하게 되면 자의반 타의반으로 많은 분이 회사를 옮기게 된다. 여기서 자의반은 합격후 자신의 능력을 펼칠 수가 있는 곳이 많이 보이기 때문에 옮기는 것이고, “타의반이라 함은 다른 곳에서 스카우트 제의가 와서 옮기게 되는 경우이다.

 

기술사에 합격을 하면 이직이나 전직을 할 때 헤드헌팅업체를 이용하는 것이 좋다. 일반적으로 헤드헌팅업체에서는 기술사가 이직과 전직을 원하면 전담 헤드헌터가 배정되는 것으로 알고 있다. 해당 헤드헌터에게 현재 상황과 앞으로 일하고 싶은 것이 동종업계 다른 회사인지, 다른 직무인지 말하고 자문을 받아보는 것이 좋겠다.

 

최근 금융회사 광고 카피 중에 전문가는 전문가의 도움을 받아야 한다는 문구가 생각난다. 헤드헌팅업체의 헤드헌터와 직접 상담을 해보면 기술사 합격과 동시에 자신이 전문가 칭호를 받는 다는 것을 알 수 있다. 기술사가 아닌 경우 특별한 전문가가 아니면 헤드헌팅업체에서 관리도 해주지 않을 것이다. 자신이 직접 여기저기 알아보면서 이력서를 몇 십장 준비해야 할 것이다.

 

이력서를 작성할 때도 기술사가 없다면 자신이 경험한 노하우와 경력을 인정 받기가 어렵다. 이력서에 빼곡하게 참여한 프로젝트와 했던 경력, 교육 내용을 전부 나열해야 하지만, 기술사의 경우는 주요한 경력만 몇 개 적으면 될 것이다.

 

최근에 다른 곳으로 이직과 전직을 한 동료 기술사들에게 물으니, 기술사를 획득하지 못했다면 지금 옮긴 회사로 옮길 수도 없었을 뿐만 아니라 몸값도 올려 받지 못했을 것이라고 한다. 또한 이력서를 작성할 때도 간략하게 작성하게 되어 무척 편했다고 한다. 면접도 긴장하지 않고 웃으면서 보았고 불합격에 대한 우려도 많이 없었다고 한다. 다만 새로 옮긴 회사에서 자신에게 많은 기대를 걸고 있기 때문에 회사가 원하는 실적을 내기위해 많이 노력해야 하는 것이 부담이라고 했다. 기술사 합격하지 못한 사람이 들으면 행복한 고민이라고 할 수 있겠다.

 

기술사가 회사를 옮길 때 공식 모집공고 때 원서를 접수해서 가는 경우는 드물다. 대체로 비공식적으로 이직 제의가 오고, 담당 임원의 면접(보통 식당이나 커피숍 같은 곳에서 진행됨)을 통해 선발되는 경우가 많다. 또한 강연회나 세미나에서 우연히 만나서 술을 한잔하는 회식자리에서도 이직과 전직에 대한 이야기가 오고 가기도 한다.

 

기술사 합격 후 높아진 몸값을 뒤로 한 채, 전혀 다른 직종의 일을 하는 분도 간혹 있다. 이런 경우는 자신이 늘 하고 싶던 일을 하는 경우이다. 기술사 합격을 하지 않고 다른 일을 한다면 전직한 해당 업계에서 저 사람은 IT 하다가 포기하고 이쪽으로 왔다고 수근거릴 수 있으나 기술사를 합격하고 나서는 해당 IT 분야를 일정 부분 완전히 정리를 하고 다시 다른 곳으로 간 경우로 인식되기 때문에 더 높은 대우를 받을 수 있다. 그리고 전직한 업종의 일을 하다가 언제라도 IT로 돌아올 수 있다. 그렇게 한다 하더라도 기존의 IT 경력과 새로운 직종의 경력이 어우러진 좋은 직업을 가질 확률이 기술사 합격을 하지 않고 옮겨간 경우 보다 월등히 높을 것이다.

 

후자의 경우를 살펴본다면, 자동차 세일즈를 하다가 IT 업계로 온 홍길동이라는 사람을 IT 업계에서 평을 할 때 홍길동이 10년 동안 평이한 수준으로 자동차 세일즈를 하다가 온 경우와 홍길동이 자동차 판매왕을 한 경험이 있는 것과 대우가 다를 것이기 때문이다. 당연히 자동차 판매왕 경험을 살려서 IT 영업에서도 발군의 실력 발휘를 할 것으로 기대하면서 대우는 좋아질 것이다.

 

다른 종목 기술사가 IT 업계로 전향한 경우도 마찬가지 경우이다. 예를 들어 교통기술사나 안전관리 기술사라고 하더라고 최근 IT에서는 지능형 교통 시스템이나 국책 사업관련 시스템이 인기를 끌고 있기 때문에 당연히 대우가 좋을 것이다.

 

정보관리기술사, 전자계산조직응용기술사도 다른 업계에서 IT와 관련되지 않은 것이 없으므로 전직을 하더라도 좋은 경험이 될 것이라고 확신한다.

 

 

u      기술사 커뮤니티의 좋은 점

 

필자는 기술사를 합격한 후 명함의 소비량이 엄청 늘어났다. 기술사 합격 전에는 명함 한 통 있으면 몇 년을 사용했고, 오히려 전화번호나 회사 직제 체계가 바뀌어 명함을 바꿔야 하는 경우가 훨씬 많았다. 외부 모임이나 커뮤니티에도 오라는 곳도 많지 않았고 갈 곳도 별로 없었다. 하지만 기술사 취득 후에는 가고 싶은 커뮤니티도 많고, 참석해야 할  모임도 많고, 별로 가고 싶지 않아도 참석해야 할 모임이 많아져서 2~3달에 명함 한 통을 다 소비하는 것 같다. 최근에는 명함 달라고 안 하면 절대 안 준다. 새로운 사람 만날 때 마다 명함 교환을 하였더니 회사에 명함 신청하기도 눈치가 보인다.

 

이렇게 명함이 새롭게 교환될 때마다 새로운 커뮤니티에 참여하게 된다. 최근 1년 동안 약 50장 넘게 받은 명함 중에는 기술사를 합격하지 않았으면 만날 수 없는 수많은 사람들을 만나게 되었다. 대표이사나 CEO 분도 많이 있고, Microsoft 기술서비스본부장, KT 본부장, H 정보기술 공공사업본부 본부장, K 정보통신 사업지원 그룹장, 이사, 컨설팅 회사 팀장, S회사 책임 컨설턴트, K 연구소장, N 정보센터 센터장, K 진흥원 센터장, K 결제원 팀장, SK K부장, D대학 교수님 등 많이 있다.

 

특히 정말 희한하게도 대통령 비서실, 대통령 경호실, 대검찰청, 국세청, 국방부 육군소령, 공군중령 , 노동부, 해양수산부, 서울시청, 교육인적자원부, 행정자치부, 국회사무처, 국회도서관, 대법원, MBC, 119 소방대, 해병대, 법무부, 인천국제공항, 철도청 등에 계신 분과도 개인적인 친분을 쌓았다.

 

재미있는 에피소드가 있는데, 대통령 경호실에 계신 분과 기술사 시험에 관한 논의를 하기 위해 전화 통화를 하게 되었는데, 필자가 지금 어디에 계시냐고 물었더니, 그분 왈 그건 보안상 말할 수 없습니다라고 대답하는 것을 듣고 그때는 긴장했지만 지금은 웃음이 나오는 재미있는 일화이다.

 

기술사를 합격하게 되면 만나는 사람도 다양해지고 많은 커뮤니티에 자연적으로 참여하게 되니, 스스로 생각해도 남부럽지 않는 것 같다. 특히 사소한 모임이 아니라 아침 일찍 호텔에서 열리는 조찬회나 IT 기술 세미나, 외부 강의를 통해서 다양한 분야의 전문가를 만나기 때문에 더욱 좋은 것 같다.

 

1년에 6번 참여하게 되어 있는 조찬회가 있다. 물론 기술사 합격 후에 참여하는 모임이다. 각계의 쟁쟁한 IT 인사들이 많이 오신다. 필자가 처음 조찬회에 참여했을 때의 감동은 쉽게 잊지 못한다. 아침 일찍 일어나 뭔가를 한다는 것도 그렇지만, 대단하신 분들을 잠시라도 만날 수 있게 되어 더욱 좋았다. 새벽에 눈 비비며 영어 학원을 다니던 뿌듯함의 100배 정도 기쁨이었다.

 

  

u      기술사 경력 활용의 무한 가능성

 

기술사를 취득하면 평생 해보지 않았던 다양한 경험을 해 볼 수가 있다. 그 경험이야 자신이 하고자 하면 얼마든지 무한하게 펼칠 수 있다. 일단 외부 강의 청탁이 들어오고, 대학교에서 강의를 할 수도 있다. 신문이나 잡지에 글 기고도 하게 된다. 대중매체에 자신의 글이 실리는 기쁨은 상당한 즐거움이다.

 

필자의 경우 기술사 취득 후에 활동한 예를 몇 가지 소개하면 다음과 같다.

 

우선 경영과컴퓨터라는 월간지의 전문가리포트라는 코너에 글이 한번 실렸다. 2004년도 4월호에 실렸는데, 이 잡지를 보고 몇 군데서 기술 자문을 원하는 전화를 받았고, 인터넷의 어느 블로그(Blog)에 가니 세상에나, 필자의 글이 출처를 명시한 채 유통되고 있었다. 해당 블로거(블로그를 작성한 사람)은 필자가 쓴 글이 마음에 들었던 모양이다. 매우 감사하고 즐거운 일이었다.

 

인터넷 웹진 ITFIND를 발간하고 있는 정보통신연구진흥원의 정보통신 기술, 정책 및 사업에 관한 주간기술 동향에도 2005년 5월 4(1194) 필자의 글이 실렸다. 최근 이슈가 되는 유비쿼터스와 개인정보보호에 관한 내용인데, 이번에는 경영과컴퓨터에 글이 실린 것보다 훨씬 많은 사람들이 자신의 블로그에 담아 놓았다. 해당 내용은 대학원 논문 작성할 때 정리했던 내용을 조금 다듬은 것인데 사람들에게 공감과 도움이 되는 것 같아 매우 기쁘다. 필자의 블로그에도 다른 사람의 블로그에 있었던 필자의 글을 “[] – 복사 해서 붙여넣기 해 놓았다.

 

외부 강의는 오라는 곳도 있고 가고 싶은 곳도 있으나, 회사 정책상 한번씩 나가는 것이 쉽지 않다. 필자의 회사에서는 강의 전 내부 승인을 받아서 출강해야 하고, 그 수익금도 일정부분 회사로 제출하는 형식을 거쳐 자동적으로 복지기금에 사용된다. 2004년도에 내부결제와 인사팀 결제를 받아 주간에 강의를 나간 기억이 있다. 행정자치부 정부정보화센터에서 IT 관련 강의를 했다.

 

그리고 SK 상무님으로부터 감사장도 받았고, 지금은 책을 집필해서 여러분과 지면으로나마 만날 수 있는 영광도 추가로 생겼다. 이렇게 기술사 취득 후에는 무한한 활용 가능성이 있다. 

 

 

u      외국의 기술사와 국가간 상호 인정 기술사 제도 (APEC / APCE)

 

일본과 미국의 기술사 제도를 살펴봄으로써 외국 기술사 제도에 대한 이해를 하고, 국가간에 기술사를 국제 자격증으로 인정하자는 논의가 진행되고 있는 APEC에 대해서 알아보자.

 

 

¤      국제적인 기준에서의 기술사, 해외 기술사

 

글로벌 시대에 살고 있는 우리는 자격증을 취득하면 이것이 외국에서도 사용할 수 있는가? 외국에서는 어떠한가? 등에 대해 매우 궁금해 한다. 독자가 원할 줄 알고 필자가 미리 다 조사를 해 놓았다. 이 글을 읽는 독자는 정말 편할 것이다. 결국 책 구입한 비용이 절대 아깝지 않은 것이다. 너무 자화자찬한 경향이 있어서 이 부분은 나중에 원고 최종 손질할 때 삭제 해야겠다.

 

우리나라는 노동부 주관(과기부 총괄)으로 기술사 자격제도를 운영하고 있으며, 한국 인력관리공단이 검정을 대행하고 있다. 외국의 경우도 대부분 기술사 자격 제도가 있는데, 일본의 경우는 우리나라와 제도가 거의 비슷하고, 영국의 경우는 교육 고용부가 관리하는 국가 자격으로 전문 직업 자격(NVQ, National Vocational Qualification)5단계에 해당하는 NVQ5 급이 기술사로 인정되고 있다. 프랑스의 경우 DP6의 경우가 기술사로 인정되고 있는데, 자격 기준은 대학의 석사, 박사 학위자 혹은 그랑제꼴(전문 대학원)의 학위를 가지고 있어야 한다. 미국의 경우는 4년제 대학 졸업 후 4년간의 실무 경험자에 한해서 기술사 자격 시험을 응시하여 합격한 경우에 기술사 자격증을 부여하고 있다.

 

¤      일본 기술사 제도

 

일본의 기술사 제도는 우리나라의 제도와 유사하게 일본의 기술사법에 의한 국가 검정에 의해서 기술사를 선발하고 있다.  우리나라와 마찬가지로 일본의 경우도 기술사 시험에 학력의 제한은 없으나, 대학 정규 과정을 졸업한 경우에는 1차 시험의 공통과목에 대한 시험을 면제해 주고 있다. 시험은 기초과목, 적성과목, 공통과목, 전문과목으로 구성된다.

 

대학에서 공학 계열의 졸업자에 대해서 1차 시험의 응시 자격을 부여하고, 1차 시험에 합격한자에게 기술사보의 자격을 부여한다. 기술사보는 우리나라의 기사 자격에 해당하는 것으로 볼 수 있다. 기술사보에 합격한 자는 통상 4년간의 지도 기술사의 지도하에 실무를 익히면 2차 시험에 응시할 자격이 부여되고, 2차 시험에 합격하면 기술사 자격을 갖게 된다. 그 외의 방법으로는 7년간의 실무 경험자에 대해서 바로 기술사 시험 자격을 주는 것으로 2차 시험에 바로 응시하여 합격하면 기술사가 될 수 있다.

 

기술사 시험의 경우 1년에 1회 보는 것으로 알려져 있으며, 매년 3~4월에 기술사 시험 접수를 실시하여 8~9월에 필기시험을 실시하고, 필기 시험 합격자에 대해서 12월에 구두 시험을 실시한다.  최종합격자는 다음해 2월에 발표하는 것으로 진행된다. 1년에 1회만 시험을 치르므로 자격 획득은 더욱 까다로운 편이다.

 

 

¤      미국 기술사 제도

 

미국의 기술사는 각 주에서 정한 주법에 따라 자격을 심사하고 자격 시험을 실시하며, 일정 기간 마다 자격을 갱신하여 자격 관리를 하고 있다. 따라서 각주마다 기술분야에 따라 자격 취득 절차, 시험 및 자격관리는 다소의 차이가 있다. 기술사 자격을 취득하는 절차는 각 주마다 차이가 있으나 일반적으로 4년제 이공계 대학을 졸업한 후 기사 시험 성격인 EIT(Engineer In Training) 시험에 합격한 자로써 4년 이상의 실무 경험을 갖춘 후 PE(Professional Engineer) 시험에 합격하여 주정부의 State Broad of Registration에 등록하면 등록 기술사(Registered Professional Engineer) 자격을 갖게 된다.

 

기술사로서의 자격 취득 및 등록은 각 주마다 시행하고 있으나, 어느 주의 기술사 자격 취득자는 다른 주에 자격 시험 없이 자격 등록이 가능하다.  또한 주에 따라서는 자기 주 이외에 거주하고 있는 타 주의 기술사에 대해서 일시적으로 자격을 부여하기도 한다.  일반적으로 기술사 가격 취득 후 4번의 자격 갱신 후에는 자격 유지가 가능하지만 수행한 업무에 부정이 있거나 중대한 기술적 과오가 있을 경우 자격이 박탈된다.

 

우리나라와 기술사 제도를 비교해 보면 미국은 정규 대학 졸업 후 4년의 실무 경력이 있으면 기술사 응시 자격이 주어지고 17개 기술 분야에 대해서 자격을 부여하고 있다.  미국은 서류 전형 및 필기 시험의 2 단계의 심사를 거치는 반면 우리나라는 필기시험, 경력심사, 구술시험의 3 단계의 심사를 거쳐야 한다.

 

<1-15> 세계 주요국가의 기술사제도 비교, 출처: 일본기술사회 www.engineer.or.jp

구분

한국

일본

미국

영국

자격 명칭

기술사

기술사

Professional Engineer

Chartered Engineer

법적 근거

국가 자격법

기술사법

각주의 PE

Royal Charter

자격인정기관

노동부

과학기술청

주등록 위원회

왕립 공학 평의회

자격 분야

22

19

19

19

심사방법

필기,경력, 구술

필기,경력, 구술

경력심사,필기

면접,필기

가격 요건

대학졸업+7년실무

대학졸업+7년실무

대학졸업+4년실무

대학졸업+4년실무

자격 갱신

없음

없음

있음

없음

합격율

10%이내

16%(1998)

35%

65%

 

¤      국가간 상호 인정 기술사 제도 (APEC / APCE)

 

급변하는 IT 기술과 글로벌화 되는 기업환경에 적극적으로 대응하고 기술적으로 리딩하기 위하여 해외 상호 인정 기술사 제도에 대한 논의가 계속되고 있다.

 

국제기술사(International Professional Engineer)제도의 정착은, 세계 경제가 WTO New Round, 도하개발아젠다(DDA), 자유무역협정(FTA)의 절대적 영향 하에서 진행 되고 있는, 기술 서비스 시장의 전면 개방에 능동적으로 대처 하기 위하여, 한국 내 기술사 자격자의 국제적 통용성 확보를 위하기도 하지만 다른 나라의 경우도 상호 인정하는 것을 원하고 있기 때문에 지속적으로 개선이 될 것으로 보여진다.

 

APEC(Asia Pacific Economic Cooperation)은 아시아, 태평양 지역의 경제협력을 위한 경제협력 기구이고 현재 21개 국가가 참여하고 있다. 이러한 경제협력 기구와 더불어 APEC Engineer (APEC 기술사) 상호인증 문제도 논의되고 있는 것이다.

 

이것을 APEC 기술사 또는 APCE라고 부른다. APCE라고 할 때는 기술사를 지칭하는 Engineer를 포함한 것이고 APEC만 할 때는 경제협력기구 자체를 말하는 것이다.

 

¤      APCE (Asia Pacific Economic Cooperation Engineer) 

 

아시아-태평양지역에서 상호 인정되는 기술사로서 가장 주도적으로 대처해 오고 있는 나라는 호주와 뉴질랜드이며, 수년 전부터 홍콩도 이의 도입을 적극적으로 검토하고 있다.  이들 국가들은 모두 정부가 법률에 의거하여 기술사자격을 부여하고 있지 않지만,  영국왕실로부터 주어진 헌장에 의거하여 공학회(Institute of Engineers) 혹은 기술사회(Institute of Professional Engineers)가 기술사 자격을 수여하고  있다.  호주, 홍콩은 공학회라는 이름으로, 뉴질랜드는 기술사회라는 이름으로 각각 부르고 있다. 최근에는 회원자격을 완화하고 있지만 본질적으로 양자 모두 기술사 자격을 가진 사람들의 모임이라고 할 수 있다.

 

3개국 모두 기술사자격을 공학회가 인정하고 있으므로 자격의 상호인정 문제도 공학회의 연합체에 주로 논의되어 왔다. 이러한 문제를 취급하는 이 지역의 연합체로서는 동아시아, 동남아시아, 태평양지역의 13개국 공학회로 구성되어 있는 동남아시아태평양공학회연합(FEISEAP: Federation of Engineering Institute of Southeast Asia and the Pacific)가 있다. 호주, 뉴질랜드, 홍콩의 3개국의 경우는 앵글로색슨계의 국가로서 미국, 영국과도 긴밀한 관계를 맺고 있기 때문에, 세계공학회연합 (WFEO: World Federation of Engineering Organization)에서도 주도적인 역할을 다하고 있다.  또한 호주와 뉴질랜드는 양국간의 경제적 이익을 고려하여 '호주-뉴질랜드 사이에 더욱 긴밀한 경제적 관계를 구축하기 위한 무역협정 (Australia-New Zealand Closer Economic Relations Trade Agreement)'19967월에 채결하였고, 이것은 1997년에  발효되었다. 이 협정에는 기술사의 상호인정에 관한 것이 포함되어 있다.

  

¤      APCE의 기술사 상호인정 프로젝트 추진 내용

 

APEC 인재양성실무위원회(APEC HRD Working Group)에서는 호주공학회의 주도 아래 APEC 회원국의 기술사를 상호 인정하는 작업을 진행하고 있다.  지금까지의 진행과정을 살펴보면 먼저 19965월 시드니에서 APEC HRD의 제1회 운영위원회를 개최하였다.  이어서 19973월 발리섬에서 제1회 작업위원회를, 19976월 멜버른에서 제2회 운영위원회, 작업위원회 합동회의를 열었다.  19978월 마닐라에서 워크숍을 개최하였으며,  11월에는 제3회의 운영 위원회을 열고 의견을 조정하였다. 그리고 1997년 연말에 최종보고서를 완성하여 APEC회원국에 발송하였다.

 

이러한 일련의 작업은 APECHRD 작업이 마무리되어 회원국이 동의한다면 기술사의 상호인정을 동의한 국가 내에서 우선적으로 실시하겠다는 의도 하에 진행되고 있다. 현재 APEC Engineer 조절위원회가 설치된 국가는 한국, 호주, 일본, 캐나다, 홍콩, 인도네시아, 말레이시아, 필리핀, 태국 9개국이며 설치 중에 있는 국가는 뉴질랜드이고,  아직 설치되지 않은 국가는 중국, 베트남, 파퓨아뉴기니아 3개국 이다.

 

¤      APCE 기술사의 의의

 

APEC 기술사로 등록된 기술사는 자국뿐만 아니라 회원국에서도 동일한 직무를 수행할 수 있으므로 기술사의 국제적 위상이 높아짐을 의미한다.  또한 자국의 기술 발전 여부에 따라 국내뿐만 아니라 해외에서도 활동할 수 있는 전기가 마련된 셈이다. 그러므로 APEC 기술사로 활동하기 위해서는 영어 등의 외국어 실력이 상당한 수준이 되어야 한다.

 

APEC 기술사가 상호 인증되면 해외의 우수한 기술 인력이 국내에서도 활동할 수 있는 여건이 마련 됨으로써, 노력하지 않는 기술사는 낙오될 것이므로 한국 기술사는 더욱더 자기 개발에 심혈을 기울여야 한다.

'Certificate' 카테고리의 다른 글

정보처리기술사 합격 혜택 (1)  (0) 2009.08.28

n        4장 기술사 너 좋은 거니?

 

u      기술사 취득 후 혜택

  

앞 장에서 기술사 전반에 관해 살펴 보았다. 이제 기술사를 취득하게 되면 좋아지는 점에 대해 하나씩 살펴보자. 기술사 합격하면 대체로 상당히 좋아한다. 또한 그 가족의 기쁨도 대단하다. 주변의 기술사를 합격한 사람들 말을 들어보면 합격 당시 본인보다 배우자가 더욱 좋아했다고 한다. 아마 몇 달 혹은 몇 년간 주말과 휴일을 가족을 포기한 채 살아 온 것에 대한 보상의 기쁨일까? 아니면 월급이 더욱 늘어나게 되는 기쁨일까? 배우자가 보는 합격한 남편 기술사 혹은 아내 기술사에 대한 글은 뒤 부분에서 별도로 다루기로 한다.

 

개인적으로는 기술사 자격증을 갖고 있음으로 인해, 국가나 사회에서 인정하는 권리를 누릴 수 있는데, 이러한 권리는 기술사법에 의한다. 즉 다른 자격증과는 달리 기술사 자격법에서 요구하는 일정한 경험 및 실력을 갖춘 자에 한해서 자격을 부여하고, 법에 의해서 자격을 보호 하고 있다. 특히 IMF와 같은 비상 사태에서 기업이나 사회에서 살아 남기 위해서는 남보다 특출한 능력을 인정 받아야만 생존이 가능한데, 이런 것들을 가능케 하는 것이 기술사 자격증이라고 할 수 있다. 또한 경기가 좋을 때는 더욱더 자기의 실력을 발휘할 수 있는 여건이 마련되는데, 이때도 기술사이기 때문에 더 많은 기회가 주어질 수 있는 것이다.

 

또한 국내의 선도적인 기업들은 정보 기술 전문가확보를 위하여 기존의 사원에게 기술 자격증 확보를 강하게 요구하고 있는 추세이다. 그리고 중요 자격증에 대해서는 급여 정책이나, 인사 정책으로 우대하고 있으며, 특히 IT회사 및 일반 기업의 정보시스템 담당부서에서는 정보처리 기술사 자격증에 대해서는 최고의 우대 정책을 실시하고 있다.

  

 

¤      각 기업에서의 기술사 지원제도와 기술사 혜택

 

국내 각 기업에서는 외부에서 기술사를 영입하기 위해 노력하고 있으며, 사내에서도 기술사를 양성하기 위해 많은 지원을 하고 있다. 기술사를 많이 보유한 기업의 경우 기업 내부의 전문가를 많이 확보하고 있으므로 인한 경쟁력의 제고 외에도 기업의 이미지 개선에 효과를 거둘 수 있기 때문이다. IT 분야에서는 삼성 SDS, LG CNS, SK C&C, 포스데이타 등 IT 개발 및 유지보수 회사와 중소 규모 IT 회사에서 특별히 지원을 많이 하게 된다. 기술사가 투입되는 프로젝트의 우수성과 안정성을 어느 정도 확보할 수 있고 시스템 개발을 의뢰한 기업으로부터 인건비도 많이 받을 수 있다. 

 

<1-11> 각 기업의 정보처리 기술사 현황 및 지원 혜택

업체

교육비지원

보유 현황

기술사 혜택

포스데이타

과거 지원

23

축하금 500만원

그리고 매월 수당 20만원

동부CNI(동부정보기술)

선택적 가능

8여명

수당 35만원 /연간420만원

대우정보시스템

지원

13

수당 30만원, 2호봉 승진

KT인포텍

지원 안함

3

수당 30만원

코스콤(한국증권전산)

합격후 지원

10여명

수당 20만원

한전 KDN

지원

20여명

수당 20만원

LG CNS

지원

50여명

수당 15만원 (진급시험에서.영어면제)

삼성SDS

지원

100여명

연봉에 포함

삼성네트웍스

지원

10여명

교육비 지원 + 50만원 추가지원(서적등)

농심데이타시스템

지원

2

수당 15만원

현대정보기술

지원

3

수당 15만원

한국HP

지원

6

500만원 상당 여행상품권

SK C&C

지원

39

축하금 300만원

국민은행

일부 지원

6

축하금 200만원

 

 

¤      아르바이트 기회 확대 

 

5일 근무를 이용하여 가족과 보내는 시간과 자기 개발에 투자하는 분도 많지만, 주말에 아르바이트 하는 분도 많다. 하지만 일반인이 용돈을 벌기 위해 막상 할 수 있는 일은 많지 않다. 기술사를 취득하면 평일 저녁 강의, 주말 강의, 감리 및 자문위원 등으로 참가하여 용돈을 꽤 버는 경우가 많다.

 

우선 강의는 기술사 관련 강의나, 다른 IT 관련 강의를 할 수 있는 기회가 많이 늘어난다. 저녁 시간 3시간 또는 주말에 3시간 정도를 강의하면 보통 20~60만원을 받게 된다. 기술사 양성과정에서 하루 3시간~4시간 강의를 하게 되면 40~80만원 정도 받게 된다. 일반 IT 과정 교육이나 자격증 교육기관에서 안정적인 시간을 확보한 채 강의를 하는 분도 많이 있다. 30만원 정도의 강의를 한 달에 3번 정도 한다면 월 90만원 정도 부수입이 생기고, 1년이면 1,000만원이 넘게 된다. 금액의 증감은 본인 하기 나름이다.

 

정보시스템 감리는 강의 보다 돈을 더 많이 번다. 공공기관 의무감리가 시행되었고 2006년 이후는 일반 기업에서 시행하는 시스템 감리가 늘어날 예정 이기 때문에 앞으로 감리에 참여하는 기회가 더욱 많아질 것이다. 감리는 3일에서 5일 정도의 짧은 감리부터 15일 이상의 장기 감리가 많다. 회사에 재직중이라면 내부 절차를 거쳐 공식적으로 감리를 나가거나, 개인적으로 휴가를 제출하고 감리에 참여할 수 있다. 3일 동안 감리를 하는 경우 보통 80~100만원 정도의 보수를 받게 된다. 감리 참여시에 총괄 감리나 주관 감리로 참여할 경우 통상 하루에 15~20만원의 보수를 더 받게 된다.

 

자문위원 또는 심사 위원으로 참석하는 경우도 있다. 이것은 약간의 나이와 경험, 경륜이 필요하다. 금액은 참여하는 기관과 참여 정도에 따라 차이가 많이 나기 때문에 평균 보수를 따지기 어렵지만, 소프트웨어사업의 노임단가 기준 기술사의 하루 임금은 다른 직급에 비해 가장 높은 약 25만원으로 되어 있기 때문에 시행 기관에서 최소 이 금액 이상은 지급하려고 하고 있다.

 

 

¤      각종 행사 참석 요청 및 식사 제의 증가 

 

필자가 기술사 합격 후 어떤 장소에 있다가 아니, 내가 이런 곳에 와 있다니, 정말 놀라운 일이군!” 이라고 느낀 적인 많다. 왜냐 하면 기술사 합격을 못했다면 정말 갈 수 없는 곳에 가 있기 때문이다.

 

삼성동 그랜드 인터콘티넨탈 호텔은 실내 장식과 분위기가 좋은 편이다. SI 회사에서 제품 설명회를 하면서 점심 식사한 기억은 몇 번 있지만 특정 주제를 듣기 위해 조찬회를 참석하는 경우는 처음이었다. 조찬회에 초대 받아 처음 갔을 때는 마음이 많이 흥분되었다. 하지만 이제 그랜드 인터콘티넨탈 호텔 조찬회는 이제 가능한 가지 않으려 한다. 참석 요청이 제일 많기도 하지만 아침 식사 메뉴로 빵이 나온다. 몇 가지가 추가로 나오긴 하지만 밥이 안 나온다.  아침에는 밥을 먹어야 하는데, 조찬회 주관하시는 분들이 조금만  신경을 쓰면 되는데 아쉽다. JW 메리어트 호텔 조찬회는 주로 밥이 나온다. 미역국, 김치,, 여러 반찬, 수정과 디저트 등 아주 좋다.

 

 

u      2008년부터 기술사 효용성이 크게 높아진다

 

2006년 하반기부터 국가기술자격 중 기술사 자격의 산업현장에서의 활용성을 제고하기 위한 방안이 추진되었다.

 

노동부는 기술사의 선발.활용 및 관리의 연계성 강화를 위하여 국가기술자격 체제하에서 기술사 자격에 대한 과학기술부의 역할 강화 근거를 규정한 국가기술자격법 시행령 개정안을 입법예고 하였고 이제 대통령령으로 시행이 되고 있다.

 

주요내용은 「국가기술자격정책심의위원회」밑에「기술사제도발전전문위원회」를 설치하여 기술사제도 발전을 위한 전문적인 사항을 조사.연구하고 기술사 종목의 신설,변경,폐지에 대하여 노동부장관이 관계부처와 협의·조정하던 것을 과학기술부장관으로 변경하였다.

또한「국가기술자격제도발전기본계획」중 기술사에 관한 사항은 과학기술부장관이 기본계획을 수립하여 노동부장관에게 제출하도록 하고 국가기술자격의 상호인증에 있어 기술사에 관한 사항은 과학기술부장관이 관장하도록 하였다.

 

그동안 기술사 제도 관련업무는 선발은 노동부, 육성 및 활용시책 수립 추진은 과학기술부, 기술용역,감리활동 수행은 건설교통부 등 15개 관련부처에 분산됨으로써 기술사 제도를 총괄하는 주관부처가 없어 우수기술사의 양성과 활용에 애로가 있었으나 앞으로는 기술사에 대하여 자격검정에서 활용 및 관리까지 체계적이고 유기적으로 추진할 수 있게 되었다.

이번 시행령 개정으로 산업현장 수요에 부응하는 고급인력을 양성함으로써 산업현장 활용성을 제고하고, 기술사의 질적 수준 향상에 기여할 수 있을 것으로 기대된다.

노동부는 그동안 국가기술자격제도가 공급자 위주로 운영되어 산업현장의 수요를 제대로 반영하지 못한다는 비판이 제기됨에 따라 자격의 현장성 및 활용성을 제고하기 위하여 자격제도 운영주체로서 산업계의 역할을 확대하고, 종목 및 등급체계를 개선하는 등 산업수요 변화에 부응하는 국가기술자격체계 및 시스템을 구축하기 위해 자격제도 혁신을 추진하고 있다고 밝혔다.

 

정보처리 기술사의 경우에는 의무감리 제도의 도입 등과 각종 제도 개선의 효과를 많이 받게 되어 금전적 활동의 증대를 볼 것이고 기술사에게 수석 감리원 자격을 부여하게 되어 그 위상도 매우 높아질 것으로 예상된다.

 

¤      2008년부터 변경될 기술사 효용성에 대한 기사

 

[과학기술부] 과기부,1차 기술사제도발전 기본계획 마련  (2007. 12. 24 뉴스 기사)

국제수준과 산업수요에 부응하는 기술사 육성·활용 체계 구축

과학기술부는 기술사제도를 산업수요(현장의 전문기술수요) 및 교육훈련제도(공학교육, 계속교육)와 연계하여 국제수준에 부합하는 기술사 자격체계를 구축하는 것을 주요 내용으로 하는 3년간의『제1차 기술사제도발전 기본계획('08∼'10)』을 마련하여 시행한다고 24일 밝혔다.

※ '07. 12. 24(월) 15:00,
기술사제도발전심의위원회 심의·확정

1차 기술사제도발전 기본계획의 주요내용은 다음과 같다.

기본계획의 비전은 기술사의 국가 기술경쟁력 제고 선도에 두고 있으며, 이를 위한 목표로는 현장기술의 최고 전문성을 갖춘 기술사의 위상과 실효성 확보를 정하고 있다.
이러한 목표를 달성하기 위해 과기부는 3개 추진전략과 9개 중점과제를 추진키로 했다.

첫째, 기술사 제도의 운영체계를 확립하여 기술사제도를 선진화 해 나가기로 했다.

둘째, 우수 기술사의 배출 및 지속적인 능력향상으로 기술사의 전문성을 강화할 계획이다.
또한, 개정된 기술사법의 시행('07.7.27)으로 3년간 90시간의 기술사 교육훈련이 의무화됨에 따라 우수한 기관을 기술사 교육기관으로 지정·운영토록 하는 한편, 철저한 사후관리를 해 나갈 계획이다.

셋째, 기술사의 활용을 확대하여 기술사 자격의 실효성을 확보하도록 할 계획이다.

이를 위해 그동안 민·관 합동 TF팀에서 도출한 "기술사 고유업무영역 설정 36개 세부추진과제"의 조속한 추진(현재 18개 완료, 18개 추진 중)과 함께, 지속적인 기술사 업무영역 발굴을 위해 관련 "상설 협의체"를 구성·운영해 나가기로 했다.
아울러, 22개 분야 89개 종목으로 지나치게 세분화되어 있는 국내 기술사 자격종목을 국제수준과 산업구조 변화에 맞게 정비할 계획이다. 단기적으로는 현행 기술분야(22)를 국제수준과 국내 산업수요에 맞게 조정하여 세부종목(89)을 함께 병기하고, 장기적으로는 기술 분야(15∼20)를 종목으로 통합하는 방향으로 기술사 자격종목을 정비할 계획이다.
또한, 국내 우수 기술사의 해외진출을 촉진하기 위해 기술사 자격의 국가간 상호인정을 적극 추진하고, 이를 위한 국내 심사등록 체계의 구축을 통하여 운영을 활성화 할 계획이다.

정부는 그동안 고도의 전문지식과 실무경험을 보유한 산업현장 최고 기술자인 기술사의 체계적 육성, 활용을 위해『기술사제도 개선방안』('05.11, 국무총리 보고)을 마련하고,·경력기술자(인정기술사)제도 개선, 기술사 고유 업무영역 확보 등을 추진해 오고 있으며, 지난 '071월에는 기술사법을 개정하여 과학기술부가 기술사의 배출에서 육성, 활용에 이르기까지 체계적으로 제도를 운영할 수 있는 틀을 마련한 바 있다.

금번에 수립·시행하는 제1차 기술사제도발전기본계획은 개정된 기술사법에 따라 처음으로 관련부처가 공동으로 수립한 중기계획으로 이를 통해 특정 부처나 종목의 이해관계를 떠나서 기술사제도라는 전체적인 틀을 체계적으로 갖추어 나갈 수 있을 것으로 기대된다고 과학기술부는 밝혔다.

 

¤      10년 후 유망직종 5가지 직업 선정 (취업-경력 포털 사이트)

 

취업-경력관리 포털 스카우트(www.scout.co.kr)는 한국고용정보원과 노동부 워크넷, 한국직업능력개발원의 자료를 토대로 임금, 안정성, 진입에의 유연성, 근무환경, 전문성의 항목을 고려, 10년 뒤 유망할 것으로 판단되는 5가지 직업을 선정했다.

1.
실버시터(Silver Sitter)

노인들의 생활을 편안하게 유지하고 건강을 관리할 인력. 실버시터가 되기 위해서는 사회복지, 노인복지, 실버케어 등을 전공하고 노인성 질환 및 건강 관리에 대한 지식과 노인특성을 고려한 상담 지식을 익히면 도움이 된다.

2.
다이어트 프로그래머(Diet Programmer)
전 세계 인구 중 무려 17억 명이 비만 또는 과체중에 해당. 이에 따른 전문가 필요


3.
정보시스템감리사
정보시스템감리사로 활동하기 위해서는 전산계통 관련 전공을 하거나, CISA(국제공인정보시스템감사사), 정보관리기술사, 정보시스템감리사 등 관련 자격을 취득하면 유리하다.

4.
헬스케어 전문가(운동치료사)


5.
여행상품기획가(Tour Planner)
5일 근무제가 본격화되면서 주말을 이용한 짧은 여행이 늘고 있다. 여행상품기획가의 필요이유이다


위의 5가지 직종 가운데 세 번째 정보시스템 감리사가 눈에 띈다. 정보처리 기술사에 합격하면 정보시스템 감리사가 하는 업무를 다 할 수 있고, 5주간의 교육만 이수하면 수석감리원이 되기 때문에 정보시스템 감리사 보다 훨씬 좋은 것이 정보처리기술사라고 할 수 있다.

 

 

¤      산업안전보건법에 기술사 우대사항 신설 예정

 

노동부공고 제2007-197호에 의하면, 법률 개정(법률 제84752007. 5.17. 공포, 2008. 1. 1. 시행 및 법률 제85622007. 7.27. 공포, 2008. 1. 1. 시행)에 따라 산업안전보건법 시행규칙 중 일부 개정령() 입법예고를 통해 기술사 우대사항을 신설한다고 밝혔다. 정보처리기술사는 대상이 아니지만 각 기관에서 기술사 우대 정책이 지속되고 있는 반가운 소식이다. (대상: 산업안전보건분야 기술사, 산업위생관리 기술사)

 

 

¤      전기공사사업법 개정안에 기술사 우대사항 신설 예정

 

산업자원부장관 명의의 전기공사업법」시행령 및 시행규칙 중 개정령()입법예고 (2007. 7. 9)에 따르면 기술사 우대조항이 신설되었다. 개정이유로 기술사 우대 정책에 따른 제도 개선 사항을 반영했다고 한다. 주요 내용은 시공능력평가 중 기술능력 평가의 경우 기술사는 3.0의 가중치를 부여한다고 한다. 정보처리기술사는 대상이 아니지만 각 기관에서 기술사 우대 정책이 지속되고 있는 반가운 소식이다. (참고로 정보통신 공사 80억 이상의 경우 기술사 참여시 시공능력평가에서 2.5점의 가산 조항이 2007년 신설되었다)

 

¤      기술사 제도 발전 기본 계획(2008 ~ 2010) 확정된 주요 내용

 

1차 기술사 제도 발전 기본 계획 (2008 ~ 2010)에서 확정된 주요 내용의 전체는 합격방법서 자료실에서 제공하기로 하고 우선 간략한 내용만 살펴본다. 우선 이 자료는 기술사 제도 개선을 총괄하는 과학기술부와 행정자치부, 농림부, 산업자원부, 정보통신부, 보건복지부, 환경부, 노동부, 건설교통부, 해양수산부, 기상청, 경찰청, 소방방재청, 농촌진흥청, 산림청 등에서 참여하여 합의한 확정내용이다. 또한 매 3년마다 기술사 제도 발전 기본계획을 수립하기로 하였다. (기술사법 제5조에 규정, ’07.1.26)

 

기술사 활용확대와 관련하여 기술사 자격의 실효성 확보를 위해 업무영역 확보 등을 통한 활용촉진과 국제 통용성 제고, 산업구조 및 국제수준에 맞는 종목을 정비하기로 했다.  

 

또한 합격자 인원수와 관련하여 그 동안 기술사 수급전망이 체계적으로 조사되지 않아 안정적 배출이 어려운 실정이었으나 기술사 수급계획을 기술사 제도발전 기본계획 수립시 장.단기 수요와 공급을 전망하도록 규정(기술사법 제5)함에 따라 기술사 수급계획(과기부)과 검정시행계획(노동부) 및 기술사 활용(주관부처)간의 상호 긴밀한 연계 협력을 통해 시행하기로 했다. 2008년부터 합격인원의 큰 증가가 예상되는 종목은 건축시공기술사, 토목시공기술사, 산림기술사, 금형기술사, 소방기술사, 토양환경기술사 등이며, 자세한 내용은 합격방법서 자료실의 해당 자료를 참조하기 바랍니다.

 

<1-11A> 정보처리 기술사 인력 수급 계획 분석 (2008 ~ 2010)

자격 종목

2006년 현황

2008년 자격수요

(주무부처 예상)

2009년 자격수요

(주무부처 예상)

2010년 자격수요

(주무부처 예상)

접수

인원

합격

인원

응시

수요

배출

수요

응시

수요

배출

수요

응시

수요

배출

수요

정보관리

기술사

1,043

61

1,500

81

1,800

97

2,158

116

전자계산조직응용기술사

249

30

309

22

344

25

387

27

- 다른 모든 종목에 대한 자료는 합격방법서 자료실에서 제공

 

 

시험 출제와 관련하여 암기력 보다는 전문지식, 이해력, 판단력을 평가할 수 있도록 시험방식을 개선하기로 하였고, 난이도 유지와 출제의 일관성 확보를 위해 출제기준을 마련하고 출제방식에 개선을 추진하기로 하였다. 또한 기술사 업무영역 확보를 위한 관련 법령 등을 조사, 분석하여 기술사 업무영역 확충을 위한 상설 협의체를 구성하고 운영하기로 했고, 기술사 활용 촉진을 위해 공공기관, 기업 등에서의 기술사에 대한 인센티브를 확대하도록 각종 시책을 마련하여 추진하기로 했다.

'Certificate' 카테고리의 다른 글

정보처리기술사 합격 혜택 (2)  (0) 2009.08.28

I am having several problems configuring incoming e-mail.  I have consulted Steve Smith's paper from Combined Knowledge on the topic (www.combined-knowledge.com/Downloads%202007.htm), but am still having problems.  I think they may be related so I am including them in a single post.

I am running MOSS 2007 SP1 (slipstreamed installation) with two WFE, one APP, and one DB server.  Service accounts are setup for least privilege.  The WFE servers have the SMTP service installed.  The services (Windows SharePoint Services Incoming E-Mail) are running on each WFE, as indicated from the Services on Server page in CA.

Problem #1:

When I " Enable sites on this server to receive e-mail " in automatic mode I immediately get two errors in the APP server Application event log once every minute:
-------
Event ID: 6872
A critical error occurred while processing the incoming e-mail drop folder . The error was: Value cannot be null.
Parameter name: path.

and

Event ID: 6398
The Execute method of job definition Microsoft.SharePoint.Administration.SPIncomingEmailJobDefinition (ID b8197cdb-92a2-4554-b3a4-46a89887878a) threw an exception. More information is included below.

Value cannot be null.
Parameter name: path
-------
I switched to advanced mode and entered the drop folder path "c:\inetpub\mailroot\drop" and the error continues.

I checked the permissions of the drop folders (there are two, one on each server since there are two WFEs that are load balanced) WSS_ADMIN_WPG and WSS_WPG had their permissions set.  I granted the CA service account full control over the drop folder, the errors continue.


Problem #2:
With incoming e-mail enabled (and generating the error above) I attempt to e-mail enable a document library.  After submitting the setting I get a non-descript error:
-------
Error
Error in the application.
Troubleshoot issues with Windows SharePoint Services.
-------

I suspect this error is because an entry cannot be made into the AD OU designated to hold


Problem #3:
As a test I sent an e-mail to the MOSS address, @sp.company.com (name changed to obscure my employer).  The e-mail bounced back and a warning was logged on the WFE server.

The System warning:
-------
Event ID: 4000
Message delivery to the remote domain 'sp.company.com' failed for the following reason: Unable to deliver the message because the destination address was misconfigured as a mail loop.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
-------

The bounced back message:
-------
Delivery has failed to these recipients or distribution lists:

thisisatest@sp.company.com
The recipient's e-mail system can't process this message at this time. Microsoft Exchange will not try to redeliver this message for you. Please try resending this message later, or provide the following diagnostic text to your system administrator.
-------

I'm still troubleshooting and will post any updates to the thread

+ Recent posts