FileStream очень медленный? - PullRequest
       20

FileStream очень медленный?

3 голосов
/ 02 февраля 2012

Я пытался скопировать 5 ГБ ISO-файл на флэш-диск 32 ГБ с 29 ГБ свободного места.

Windows 7 отказалась разрешить мне перетаскивание файл на флэш-диск, сообщая, что файл слишком велик для целевой файловой системы.

В конце концов я узнал, что это потому, что диск был отформатирован как FAT32 вместо NTFS , но не раньше, чем я написал эту процедуру для копирования файла:

private void copyFile(string from, string to) {
  bool ok = true;
  using (StreamReader sr = new StreamReader(from, true)) {
    using (StreamWriter sw = new StreamWriter(to, false, sr.CurrentEncoding)) {
      int FOUR_K = 4048;
      char[] buf = new char[FOUR_K];
      try {
        while (-1 < sr.Peek()) {
          int len = sr.Read(buf, 0, FOUR_K);
          sw.Write(buf, 0, len);
          sw.Flush();
        }
      } 
      catch (Exception err) {
        ok = false;
        throw err;
      }
    }
  }
  if (ok) {
    Console.WriteLine("Done!");
  }
}

Я позволил ему работать около часа, и он только добрался доРазмер файла 270 МБ.

Что происходит?

Что в моем коде заставляет мой файл занимать так много времени?

Это мой выбор FOUR_Kпеременный размер?

[ОБНОВЛЕНИЕ]

У меня есть два файла ISO: Win8-32bit при ~ 3 ГБ и Win8-64bit-Разработчик на ~ 5 ГБ.Используя функцию перетаскивания, проводник Windows скопировал файл объемом 3 ГБ на мою флэш-накопитель объемом 32 ГБ примерно за три минуты.

Используя метод Марка Грэйвела , я повторил это еще раз:

[STAThread]
static void Main(string[] args) {
  using (OpenFileDialog dlg = new OpenFileDialog()) {
    dlg.Title = "Select File";
    if (dlg.ShowDialog() == DialogResult.OK) {
      using (FolderBrowserDialog fdg = new FolderBrowserDialog()) {
        fdg.Description = "Select Destination";
        if (fdg.ShowDialog() == DialogResult.OK) {
          DateTime start = DateTime.Now;
          Console.WriteLine("Started at {0:g}.\nWorking...", start);
          using (FileStream fin = File.Open(dlg.FileName, FileMode.Open)) {
            using (FileStream fout = new FileStream(Path.Combine(fdg.SelectedPath, dlg.SafeFileName), FileMode.Create)) {
              try {
                fin.CopyTo(fout);
              } catch (Exception err) {
                Console.WriteLine("An Error Occurred:");
                Console.WriteLine(err.Message);
              }
            }
          }
          DateTime end = DateTime.Now;
          TimeSpan span = (end - start);
          Console.WriteLine("Process Ended at {0}.\nThe total minutes passed = {1}.", end, span.TotalMinutes);
          Console.WriteLine("Press Any Key.");
          Console.ReadKey();
        }
      }
    }
  }
}

Используя вышеприведенные примеры FileStream, программа работала в течение примерно 8 часов, копировала ровно 4,194,300 KB и затем выдавала исключение «Недостаточно памяти».

Ответы [ 3 ]

8 голосов
/ 02 февраля 2012

Я не знаю о проблеме производительности (звучит очень странно), но нет никакой причины использовать StreamReader / StreamWriter здесь вообще , так как вы можете просто скопировать в двоичный файл уровень. Действительно, ISO-образ - это не текст , поэтому чтение его в char данных может привести к повреждению. Для информации, даже если вы не хотите использовать File.Copy, все, что вам нужно здесь:

using(var inFile = File.OpenRead(source))
using(var outFile = File.Create(destination))
{
    inFile.CopyTo(outFile);
}

Чтобы получить 270 КБ в час, вам нужно очень постараться (если IO в основном не работает); я думаю, что это где-то выдало ошибку.

3 голосов
/ 02 февраля 2012

Я подозреваю, что это Flush звонок каждый раз.

Если вы используете .NET 4, в Stream теперь есть метод CopyTo:

using (var input = File.OpenRead(fromFile))
{
  using (var output = File.OpenWrite(toFile))
  {
    input.CopyTo(output);
  }
}
2 голосов
/ 02 февраля 2012

Если вы пытаетесь скопировать двоичный файл, почему вы используете StreamReader/StreamWriter? Попробуйте что-то вроде этого:

using (FileStream source = File.Open(@"c:\Source\data.iso", FileMode.Open))
{
    FileStream destination = new FileStream(@"F:\Desitnation\data.iso",FileMode.OpenOrCreate));

    source.CopyTo(destination);
    destination.Close();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...