2013-02-10 5 views
11

Я использую этот код, чтобы извлечь кусок из файлаулучшить скорость расщепления файла

// info is FileInfo object pointing to file 
var percentSplit = info.Length * 50/100; // extract 50% of file 
var bytes = new byte[percentSplit]; 
var fileStream = File.OpenRead(fileName); 
fileStream.Read(bytes, 0, bytes.Length); 
fileStream.Dispose(); 
File.WriteAllBytes(splitName, bytes); 

Есть ли способ, чтобы ускорить этот процесс?

В настоящее время для файла объемом 530 МБ требуется около 4 - 5 секунд. Может ли это время быть улучшено?

+1

извлечение 50% файла неэффективно [почему 4kb до 8kb] (http://stackoverflow.com/a/5911016/495455). Если у вас есть .Net 4 или более, вы можете использовать [Файлы с памятью] (http://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile.aspx) –

+1

Что такое производительность вашего диска система? 100 МБ/с действительно звучит довольно разумно. –

+0

Могу ли я спросить, для чего вы разбиваете файл? Является ли разделение файла конечным результатом или это промежуточный шаг для решения другой проблемы? –

ответ

8

Есть несколько случаев, о которых вы спрашиваете, но Ни один из них не является родным языком.

Ниже приведены то касаются

  • Что такое файловая система файла источника/назначения?
  • Вы хотите сохранить исходный файл?
  • Они лежат на одном диске?

В C#, вы почти не метод может быть быстрее, чем File.Copy, призывающее CopyFile из WINAPI внутри. Однако из-за этого процент составляет 50, однако следующий код может быть не быстрее. Он копирует весь файл, а затем установить длину файла назначения

var info=new FileInfo(fileName); 
var percentSplit=info.Length*50/100; // extract 50% of file 

File.Copy(info.FullName, splitName); 
using(var outStream=File.OpenWrite(splitName)) 
    outStream.SetLength(percentSplit); 

Далее, если

  1. вы не держите оригинал после файла расщепляется
  2. диск назначения является таким же, как источник
  3. ваш не используя сжатие включена файловая система шифрования/

то, лучшее, что вы можно сделать, не копировать файлы вообще. Например, если исходный файл находится на FAT или FAT32 файловой системы, что вы можете сделать, это

  1. создать новую запись директории (записи) для вновь расщепленных частей файла
  2. пусть запись (запись) точка (s) к кластеру целевой части (частей)
  3. установить размер правильный файл для каждой записи
  4. чек на сшивку и избежать этого

Если ваша файловая система пром s NTFS, вам, возможно, потребуется потратить много времени на изучение спецификации.

Удачи вам!

+0

+1: Кен, я удалил свой ответ, поскольку обнаружил довольно серьезную ошибку, которая означала, что мой подход не выполнялся надежно, и однажды исправленный был на самом деле намного медленнее, чем ваш. Мне будет очень интересно узнать, может ли что-то на самом деле превзойти производительность 'File.Copy'. –

+0

Это действительно хороший ориентир для любого предлагаемого решения, которое должно работать примерно в два раза быстрее. Предполагая, что File.Copy() работает с максимальным значением данной системы, копирование только половины из них занимает примерно половину этого времени. – Hazzit

-1

Я думаю, что самый быстрый способ обойти эту проблему через двоичный буферный ввод файла.

Я не очень хорошо знаком на C#, но вы можете изучить некоторые методы буферизации для перехода к определенной части файла и выполнения буферизированного ввода из этой части.

Вы также можете прибегнуть к использованию C++ с Windows API для собственных методов буферизации или найти библиотеки, которые имеют быстрые методы буферизации.

Я не могу предложить ничего другого, надеюсь, это поможет.

0

Я получаю лучшие результаты при чтении/записи кусками в несколько мегабайт. Производительность изменяется также в зависимости от размера куска.

FileInfo info = new FileInfo(@"C:\source.bin"); 
FileStream f = File.OpenRead(info.FullName); 
BinaryReader br = new BinaryReader(f); 

FileStream t = File.OpenWrite(@"C:\split.bin"); 
BinaryWriter bw = new BinaryWriter(t); 

long count = 0; 
long split = info.Length * 50/100; 
long chunk = 8000000; 

DateTime start = DateTime.Now; 

while (count < split) 
{ 
    if (count + chunk > split) 
    { 
     chunk = split - count; 
    } 

    bw.Write(br.ReadBytes((int)chunk)); 
    count += chunk; 
} 

Console.WriteLine(DateTime.Now - start); 
+0

Вы не должны выделять куски размером более 85 КБ. см. примечание дьявола в вопросе. –

+0

Выделение фрагментов размером более 85k в порядке. На самом деле, чем больше, тем лучше, если вы как можно больше используете этот кусок. Единственная проблема - фрагментация кучи больших объектов, которая может привести к исключению из памяти. Повторное использование большого буфера предотвратит это, и когда буфер больше не будет использоваться (и потребуется память), он будет собран. Нет проблем. –

2
var percentSplit = (int)(info.Length * 50/100); // extract 50% of file 
var buffer = new byte[8192]; 
using (Stream input = File.OpenRead(info.FullName)) 
using (Stream output = File.OpenWrite(splitName)) 
{ 
    int bytesRead = 1; 
    while (percentSplit > 0 && bytesRead > 0) 
    { 
     bytesRead = input.Read(buffer, 0, Math.Min(percentSplit, buffer.Length)); 
     output.Write(buffer, 0, bytesRead); 
     percentSplit -= bytesRead; 
    } 
    output.Flush(); 
} 

Румянец может быть не нужен, но это не больно, это было очень интересно, изменяя петлю на делать, в то время как, а не в то время как был большой удар по производительности , Я полагаю, что ИЛ не так быстро. Мой компьютер запускал исходный код через 4-6 секунд, вложенный код, казалось, работал примерно через 1 секунду.

Смежные вопросы