c# - How to create fast and efficient filestream writes on large sparse files -
i have application writes large files in multiple segments. use filestream.seek position each wirte. appears when call filestream.write @ deep position in sparse file write triggers "backfill" operation (writeing 0s) on preceding bytes slow.
is there more efficient way of handling situation?
the below code demonstrates problem. initial write takes 370 ms on machine.
public void writetostream() { datetime dt; using (filestream fs = file.create("c:\\testfile.file")) { fs.setlength(1024 * 1024 * 100); fs.seek(-1, seekorigin.end); dt = datetime.now; fs.writebyte(255); } console.writeline(@"write ms: " + datetime.now.subtract(dt).totalmilliseconds.tostring()); }
ntfs support sparse files, there no way in .net without p/invoking native methods.
it not hard mark file sparse, know once file marked sparse file can never converted in non sparse file except coping entire file in new non sparse file.
example useage
class program { [dllimport("kernel32.dll", setlasterror = true, charset = charset.auto)] private static extern bool deviceiocontrol( safefilehandle hdevice, int dwiocontrolcode, intptr inbuffer, int ninbuffersize, intptr outbuffer, int noutbuffersize, ref int pbytesreturned, [in] ref nativeoverlapped lpoverlapped ); static void markassparsefile(safefilehandle filehandle) { int bytesreturned = 0; nativeoverlapped lpoverlapped = new nativeoverlapped(); bool result = deviceiocontrol( filehandle, 590020, //fsctl_set_sparse, intptr.zero, 0, intptr.zero, 0, ref bytesreturned, ref lpoverlapped); if(result == false) throw new win32exception(); } static void main() { //use stopwatch when benchmarking, not datetime stopwatch stopwatch = new stopwatch(); stopwatch.start(); using (filestream fs = file.create(@"e:\test\test.dat")) { markassparsefile(fs.safefilehandle); fs.setlength(1024 * 1024 * 100); fs.seek(-1, seekorigin.end); fs.writebyte(255); } stopwatch.stop(); //returns 2 sparse files , 1127 non sparse console.writeline(@"write ms: " + stopwatch.elapsedmilliseconds); } }
once file has been marked sparse behaves excepted behave in comments too. don't need write byte mark file set size.
static void main() { string filename = @"e:\test\test.dat"; using (filestream fs = new filestream(filename, filemode.create)) { markassparsefile(fs.safefilehandle); fs.setlength(1024 * 1024 * 25); } }
Comments
Post a Comment