2012-08-17 2 views
0

나는 파일 시스템에서 작동하는 응용 프로그램을 작성 중입니다. 앱이 처음 시작될 때, 빠른 루틴을 실행하여 요청 된 파일과 폴더를 나중에 (시간 집약적 인) 처리를 위해 메모리에로드합니다. (아래 코드 참조). 이 시점에서 진행률 표시 줄을 표시하는 데 중요한 파일의 수를 계산합니다."var"를 전역 또는 영구으로 만들려면 어떻게해야합니까?

일단 개수와 파일 데이터가 있으면 나중에 처리 할 수 ​​있도록 데이터를 저장해야합니다 (예 : 전역 변수 또는 속성 또는 클래스). 문제는 LINQ를 사용하기 때문에 필요에 따라 "var"로 저장된다는 것입니다. 변수를 깨고 검사하면 SelectQueryOperator와 AnonymousType이 다소 복잡하게 혼합되어 저장됩니다.

내 첫 번째 생각은 데이터를 반복하여 목록 <> (예 : 파일 이름과 경로 저장)로 저장할 수있는 간단한 데이터로 변환했지만 말 그대로 처리하는 데는 최대 10 분이 소요됩니다. 또는 그 이상 - 처리 할 수 ​​있습니다. 나중에 처리하기 위해 나중에 모든 데이터를 반복해야 할 것입니다. 사용자가 앉아서 목록을 먼저 만들 때까지 기다릴 방법이 없습니다.

이 데이터를 나중에 다른 것으로 변환하지 않고도 나중에 액세스 할 수 있도록 저장할 수 있습니까?

var fileNames = 
from dir in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories) 
select dir; 

var fileContents = from file in fileNames.AsParallel() 
// Use AsOrdered to preserve source ordering 
let extension = Path.GetExtension(file) 
let Text = File.ReadAllText(file) 
select new { Text, FileName = file }; 
+1

아마도 시간이 걸리는 File.ReadAllText 일 것입니다. 여기서해야합니까? 나중에 처리하기 위해 파일 이름을 저장하지 않으시겠습니까? – Polyfun

+0

모든 파일의 전체 텍스트를 저장할 충분한 메모리가 없을 수도 있습니다. – Servy

답변

1

의이 조금, 또한 어디 var 명시하게 단순화합시다 우리는 ..

정확히
var fileNames = 
from dir in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories) 
select dir; 

이 동일한 같은 : 지금

IEnumerable<string> fileNames = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories) 

:

var fileContents = from file in fileNames.AsParallel() 
// Use AsOrdered to preserve source ordering 
let extension = Path.GetExtension(file) 
let Text = File.ReadAllText(file) 
select new { Text, FileName = file }; 

는 한 줄을 위해 가기로 정확히 동일

var fileNames = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories); 

-wonder는 일반적으로 가독성을 높이는데 도움이되지 않지만 객체 생성을 모두 도와줍니다. 토론을 위해서 NE 장소 : 익명 T에 대한 ParallelQuery<T>입니다

var fileContents = from file in fileNames.AsParallel() 
select new { Text = File.ReadAllText(file), FileName = Path.GetExtension(file) }; 

. 우리가 익명 클래스를 사용 중지해야 우리가 저장할 수있는이 일을하려면

private class NameAndContents 
{ 
    public string Text{get;set;} 
    public string FileName{get;set;} 
} 

ParallelQuery<NameAndContents> fileContents = from file in fileNames.AsParallel() 
select new NameAndContents{ Text = File.ReadAllText(file), FileName = Path.GetExtension(file) }; 

유형 ParallelQuery<NameAndContents>의 분야에서 그 저장에서 당신을 중지 아무것도 지금은 없다.

두 가지 방법으로 여기에 비록 논리에 확인 할 수 있습니다 : Directory.EnumerateFiles

  1. 작용이 다음을 계산하기 위해 주어진 반복의 값을 알 필요가 있도록한다. (이것은 Windows API 함수 FindNextFile을 기반으로합니다.) 이것은 평행을 이루지 못하게 만듭니다.ReadAllText에 내재되어있는 고유 한 대기 상태가 얼마나 균형을 이루는지 예상하기는 어렵습니다. 비 병렬 버전에 대해서만 테스트 할뿐만 아니라 모든 변경 사항이 새로운 방식으로 균형을 포기할 것이므로 변경 한 후에 다시 테스트 할 것입니다.

  2. 여기서 가장 큰 히트는 ReadAllText입니다. 더 많은 주문형으로 텍스트를 사용하는 것으로 대체하는 것이 가능하다면 큰 승리가 될 수 있습니다.

+0

몇 가지 아주 좋은 정보를 주셔서 감사합니다 (그리고 다른 모든 사람들은 솔직하게). 무엇보다도, 이것은 프로그래머 (나)가 코드를 자르고 붙이며 서두르는 것을 이해하지 못하는 문제였습니다. 내 목표는 가능한 가장 빠른 방법으로 작업해야하는 파일 목록을 얻는 것이 었습니다. 그러나 ReadAllText, filesize 또는 다른 것을 필요로하지는 않았지만 나중에 반복 할 수있는 파일/경로 목록 만 가져 와서 진행 상황을 표시 할 수있게되었습니다. 불필요한 모든 비트를 제거하는 것은 매우 빨랐으며, 멋진 목록을 남겨 두었습니다 을 사용합니다. –

0

모든 데이터를로드하고 나중에 처리하기 위해 유지하는 것은 거의 잘못된 생각입니다. 당신이해야 할 일은 하나씩 파일을 로딩하고 당신이가는대로 처리하는 것이고, 어떤 경우라도 저장할 필요가 없습니다.

귀하의 질문에 답변하려면 : 조작 결과를 익명 유형 이외의 것으로 투사하십시오. 만큼 당신이하지 전화 .ToList() 또는이 변수에 유사한, 당신은 즉시 파일과 그 내용을 열거 할 수 할

class FileData 
{ 
    string FileName { get; set; } 
    string Contents { get; set; } 
} 

var fileContents = from file in fileNames 
        select new FileData 
        { 
         FileName = Path.GetExtension(file), 
         Contents = File.ReadAllText(file) 
        }; 

: 예를 들어, 클래스를 만들 수 있습니다.

Sidenote :이 작업의 병목 현상은 CPU가 아닌 파일 시스템이므로 .AsParallel() 호출을 제거했습니다.

+0

나는 원칙적으로 이에 동의하지만 현재로서는이 과정을 제안하는 Todd의 요구 사항에 대한 정보가 충분하지 않습니다. 게시물에서 언급 한 것보다 Todd의 응용 프로그램에 대한 자세한 정보를 알고 있지 않은 한. –

+0

나도. 파일 시스템의 병렬 처리 된 열거 자 = 내 책에서 요청했습니다. –

2

LINQ를 사용하고 있으므로 필요에 따라 "var"로 저장되는 것이 문제입니다.

는 아니, 당신은 var를 사용하는가 요구하는 LINQ에 대해 아무것도 없다. 기본적으로 var을 사용하면 메서드 내에서 강력한 형식의 방식으로 익명 형식을 사용할 수 있습니다.

익명 형식을 명명 된 형식으로 변환하면 var처럼 정확히 성능이이됩니다. ToList을 사용할 때의 차이점은 단순히 까지을 쿼리 할 때 실제로 아무 것도하지 않을 것입니다. 파일 시스템을 전혀 사용하지 않는 것으로 의심됩니다. (처음에 Directory.EnumerateFiles에 대한 쿼리식이있는 이유는 분명하지 않습니다.)

데이터를 일찍로드해야하거나 그렇지 않으면 질문에 명확하지 않지만 var 부분이 전부입니다. 그 직교.

파일 시스템에서 병렬 처리를 사용하면 도움이되는 것보다 방해가 될 수 있습니다.

1

로컬 변수가 아닌 경우 var을 사용할 수 없습니다. (This is why.) 코드를 유지해야하는 사람을 정말로 싫어할 경우 object 또는 dynamic으로 저장하고 익명으로 저장 한 정보를 여러 가지 해킹 방법 중 하나로 사용할 수 있습니다. object,하지만 그건 좋은 생각이 아닙니다.

정말로 가장 좋은 방법은 TextFileName 속성을 가진 새로운 유형을 만들고 익명 유형이 아닌이를 사용하는 것입니다. 미래의 개발자들에게 가장 간단하고 의미있는 수단입니다.

0

 List<string> files = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories).ToList(); 

뭐가 잘못 됐는지 정말 실제로 모든 파일을 읽을해야합니까? 그런데

는, VAR는, VAR 컴파일러 "단지 컴파일러 속기 내가

List<type> a = new List<type>() 

때마다 당신에게처럼 가진 코드를 피할 수 있도록 여기에 나를 위해 오른쪽의 유형을 쓰고, 동적 입력됩니다 아니다 그것은 실제의 형태로 대체 할 수있다 "VAR"을 참조하십시오.

을 나는 또한 "AsParallel은"여기에 도움이하도록되어 표시되지 않습니다.