2012-06-08 4 views
3

저는 미디어 플레이어를 디자인하고 있으며 Movie 클래스를 디자인했습니다. Movie 클래스에는 MediaInfo에서 상속 한 MovieInfo 멤버가 있습니다. MediaInfo에는 파일 길이, 파일 크기, 파일 경로 등과 같이 동영상 파일의 메타 데이터를 나타내는 여러 가지 속성이 있습니다.이 정보를 추출하기 위해 Shell32를 사용합니다.Shell32 메서드 호출을 최적화하는 방법은 무엇입니까?

문제는 Shell32에서 제공되는 메서드가 매우 느린 것입니다. 데이터베이스에 1 개의 영화가 있으면 문제가되지 않지만 영화 10 편이되면 눈에 띄기 시작합니다. 영화 100 편으로 프로그램로드에 약 5 분이 걸리고 몇 분 안에 다시 초기화해야합니다. 런타임 동안 영화, 다시 프로그램의 흐름을 중단합니다.

/// <summary> 
    /// Gets a Shell32 Folder, initialized to the directory of the file path. 
    /// </summary> 
    /// <param name="path">A string representing the file/folder path</param> 
    /// <returns>The Shell32 Folder.</returns> 
    public static Folder GetShellFolder(string path) 
    { 
     //extract the folder subpath from the file path 
     //i.e extract "C:\Example" from "C:\Example\example.avi" 

     string directoryPath = new FileInfo(path).Directory.ToString(); 

     return new Shell().NameSpace(directoryPath); 
    } 

그리고 Shell32Processing.GetShellFolderItem 방법 :

/// <summary> 
    /// Gets a Shell32 FolderItem, initialized to the item specified in the file path. 
    /// </summary> 
    /// <param name="path">A string representing the file path.</param> 
    /// <returns>The Shell32 FolderItem.</returns> 
    /// <exception cref="System.ArgumentException">Thrown when the path parameter does not lead to a file.</exception> 
    public static FolderItem GetShellFolderItem(string path) 
    { 
     if (!FileProcessing.IsFile(path)) 
     { 
      throw new ArgumentException("Path did not lead to a file", path); 
     } 

     int index = -1; 

     //get the index of the path item 
     FileInfo info = new FileInfo(path); 
     DirectoryInfo directoryInfo = info.Directory; 
     for (int i = 0; i < directoryInfo.GetFileSystemInfos().Count(); i++) 
     { 
      if (directoryInfo.GetFileSystemInfos().ElementAt(i).Name == info.Name) //we've found the item in the folder 
      { 
       index = i; 
       break; 
      } 
     } 

     return GetShellFolder(path).Items().Item(index); 
    } 

호출 할 때마다

다음
/// <summary> 
    /// Initializes all the information variables of the class. 
    /// </summary> 
    private void Initialize() 
    { 
     Folder mediaFolder = Shell32Processing.GetShellFolder(this.path); 

     FolderItem media = Shell32Processing.GetShellFolderItem(this.path); 

     //initialize bit rate value 
     this.bitrate = mediaFolder.GetDetailsOf(media, 28); 

     //initialize date accessed value 
     this.dateAccessed = mediaFolder.GetDetailsOf(media, 5); 

     //initialize date created value 
     this.dateCreated = mediaFolder.GetDetailsOf(media, 4); 

     //initialize date modified value 
     this.dateModified = mediaFolder.GetDetailsOf(media, 3); 

     //initialize data rate value 
     this.dataRate = mediaFolder.GetDetailsOf(media, 279); 

     //initialize file name value 
     this.fileName = mediaFolder.GetDetailsOf(media, 155); 

     //initialize file type value 
     this.fileType = mediaFolder.GetDetailsOf(media, 181); 

     //initialize folder value 
     this.folder = mediaFolder.GetDetailsOf(media, 177); 

     //initialize folder name value 
     this.folderName = mediaFolder.GetDetailsOf(media, 175); 

     //initialize folder path value 
     this.folderPath = mediaFolder.GetDetailsOf(media, 176); 

     //initialize frame height value 
     this.frameHeight = mediaFolder.GetDetailsOf(media, 280); 

     //initialize frame rate value 
     this.frameRate = mediaFolder.GetDetailsOf(media, 281); 

     //initialize frame width value 
     this.frameWidth = mediaFolder.GetDetailsOf(media, 282); 

     //initialize length value 
     this.length = mediaFolder.GetDetailsOf(media, 27); 

     //initialize title value 
     this.title = FileProcessing.GetFileTitle(this.path); 

     //initialize total bitrate value 
     this.totalBitrate = mediaFolder.GetDetailsOf(media, 283); 

     //initialize size value 
     this.size = mediaFolder.GetDetailsOf(media, 1); 
    } 

가 Shell32Processing.GetShellFolder 방법입니다 :

Mediainfo를 생성자는 초기화 메소드를 호출 GetDetailsOf (Shell32에서 제공되는 코드)는 n 엄청난 처리 시간 - ANTS 프로파일 러를 사용하여이 프로그램을 찾았습니다. 처음에는 프로그램이 너무 느려졌는지 확인할 수 없었기 때문입니다.

그래서 질문입니다 : 어떻게 Shell32 메서드를 최적화 할 수 있습니까? 그렇지 않으면 대안이 있습니까?

답변

9

코드에서 잘못하고있는 것들이 많이 있습니다. 문제는 제공 한 코드의 바깥에 있지만, 어쩌면 손상된 부분을 수정하여 어딘가에 도달 할 수 있습니다.

public static Folder GetShellFolder(string path) 
{ 
    //extract the folder subpath from the file path 
    //i.e extract "C:\Example" from "C:\Example\example.avi" 

    string directoryPath = new FileInfo(path).Directory.ToString(); 

    return new Shell().NameSpace(directoryPath); 
} 

당신은 외출 단지 파일 경로 ( new FileInfo(path).Directory)의 디렉토리 부분을 얻기 위해 파일 시스템에 액세스하고 있습니다. System.IO.Path.GetDirectoryName(path)으로 디스크 드라이브를 치지 않고이 작업을 수행 할 수 있습니다.

새 항목 처리를 시작할 때마다 새 셸 개체가 만들어집니다. 하나를 만들고 모든 항목을 처리 한 다음 릴리스합니다.

public static Folder GetShellFolder(Shell shell, string path) 
{ 
    //extract the folder subpath from the file path 
    //i.e extract "C:\Example" from "C:\Example\example.avi" 
    string directoryPath = System.IO.Path.GetDirectoryName(path); 

    return shell.NameSpace(directoryPath); 
} 

을 그리고 당신의 Initialize 방법에 Shell 개체를 전달할 : 그럼이 같은 GetShellFolder을 변경할 수 있습니다. 다음 위로 GetShellFolderItem.

public static FolderItem GetShellFolderItem(string path) 
{ 
    if (!FileProcessing.IsFile(path)) 
    { 
     throw new ArgumentException("Path did not lead to a file", path); 
    } 

    int index = -1; 

    //get the index of the path item 
    FileInfo info = new FileInfo(path); 
    DirectoryInfo directoryInfo = info.Directory; 
    for (int i = 0; i < directoryInfo.GetFileSystemInfos().Count(); i++) 
    { 
     if (directoryInfo.GetFileSystemInfos().ElementAt(i).Name == info.Name) //we've found the item in the folder 
     { 
      index = i; 
      break; 
     } 
    } 

    return GetShellFolder(path).Items().Item(index); 
} 

첫 번째 실수는 사용 전에 해당 파일에 액세스하는 "파일이 존재"여기에 다시 코드입니다. 이러지 마. 파일에 액세스하기 만하면 존재하지 않으면 FileNotFoundException이 발생합니다. 당신이하는 일은 이미 끝내게 될 추가 작업을 추가하는 것뿐입니다. 당신이 그것을하든하지 않든, 여전히 "파일 존재 테스트"를 통과 할 수는 있지만 액세스가 불가능합니다.

다음은 폴더의 파일 색인을 가져 오기 위해 디렉토리를 구문 분석합니다. 이것은 심각한 경쟁 조건입니다. 여기에서 잘못된 색인 값을 얻을 수 있습니다. FolderFolderItem을 얻는 방법을 노출하기 때문에 ParseName도 필요하지 않습니다.

마지막으로, Folder (GetShellFolder를 호출하여)을 작성하고 또 다른 Shell 항목을 작성합니다. 이미 Folder을 사용하고 있습니다.

FolderItem media = mediaFolder.ParseName(System.IO.Path.GetFileName(path)); 

그리고 우리는 그냥 깔끔하게 GetShellFolder 제거 할 수 있습니다 :

그래서 우리는 완전히 제거하여 GetShellFolderItem을 변경할 수 있습니다

private void Initialize(Shell shell) 
{ 
    Folder mediaFolder = null; 
    FolderItem media = null; 
    try 
    { 
     mediaFolder = shell.NameSpace(Path.GetDirectoryName(path)); 
     media = mediaFolder.ParseName(Path.GetFileName(path)); 

     ... 
    } 
    finally 
    { 
     if (media != null) 
      Marshal.ReleaseComObject(media); 
     if (mediaFolder != null) 
      Marshal.ReleaseComObject(mediaFolder); 
    } 
} 

이의 그 모든 만드는 차이의 정도를 살펴 보자 .

당신은 또한 당신이 이미 알고 또는 미디어 객체에서 얻을 수있는 것들에 대한 GetDetailsOf를 호출 :

//initialize folder name value 
    this.folderName = mediaFolder.GetDetailsOf(media, 175); 

    //initialize folder path value 
    this.folderPath = mediaFolder.GetDetailsOf(media, 176); 

    //initialize size value 
    this.size = mediaFolder.GetDetailsOf(media, 1); 

변경 다음에 :

//initialize folder path value 
    this.folderPath = Path.GetDirectoryName(path); 

    //initialize folder name value 
    this.folderName = Path.GetFileName(folderPath); 

    //initialize size value 
    this.size = media.Size; 
+0

당신을 감사 할 수 있습니다! 그게 문제를 완전히 고쳐주지는 못했지만, 여전히 눈에 띄는 지연이 있습니다. 그러나 지금은 훨씬 짧습니다. :) – Daniel

+1

@Daniel 또한 COM 객체이므로 출시하는 것을 잊지 마십시오. 가장 정확한 방법을 보여주기 위해 위의 Initialize를 업데이트했습니다. 'Marshal'은'System.Runtime.InteropServices' (mscorlib)에 있습니다. – Tergiver

+0

오, 그럴 필요가 있는지 몰랐습니다. 감사 :) – Daniel

0

확인이 Link. GetDetailsOf()와 Win-OS 버전을 기반으로하는 파일 속성에 대한 자세한 정보가 제공됩니다.

List<string> arrHeaders = new List<string>(); 

Shell shell = new ShellClass(); 
Folder rFolder = shell.NameSpace(_rootPath); 
FolderItem rFiles = rFolder.ParseName(filename); 

for (int i = 0; i < short.MaxValue; i++) 
{ 
     string value = rFolder.GetDetailsOf(rFiles, i).Trim(); 
     arrHeaders.Add(value); 
} 

희망이 .. 어떤 사람에게 도움이

관련 문제