[Homework]AdvancedC# - Files and Streams
Домашното не е качено . Може ли да го качите ? Друг път се качват презентацията, демата, домашното първи след това и видеото .
Евентуално темата може да се ползва и за споделяне на решения по домашното .
Домашното не е качено . Може ли да го качите ? Друг път се качват презентацията, демата, домашното първи след това и видеото .
Евентуално темата може да се ползва и за споделяне на решения по домашното .
И аз имам въпрос за Problem 5. Slicing Files - стигнах до работещо решение, което уж изпълнява всички условия на задачата: взема инпут файл, разцепва го на файлове с равен размер и със същия extension, после събира малките файлове отново в цял assembled файл:
Изпробвах решението със следните инпут файлове:
.txt file - всички парчета и assembled.txt работят идеално
.jpg file - всички парчета са damaged според windows photo viewer, assembled.jpg се отваря нормално
.avi file - само първото парче се play-va нормално - всички други парчета не се play-ват, assembled.avi се play-ва нормално.
Може ли нещо да се подобри или с някои типове инпут файлове създадените парчета ще си останат дефектни и неизползваеми?
Ето кода - предварително благодаря за всякакви идеи :)
Само първото парче можеш да отвориш, понеже всеки бинарен файл съдържа в началото си няколко байта описание за себе си. Без тях програмата, която го отваря, няма как да знае какво чете (mp3, avi, png и т.н.). Нормално е, когато нарежеш един файл на няколко части, хедърите му да останат само в първата част и затова плейърът разпознава само нея като валиден .avi файл.
Относно кода:
Аз зациклих на това: http://pastebin.com/yhQqMccP
Не мога да разбера защо ми дава Exception, че параметрите в четенето indexRead и buffer.Length са невалидни.
.Read(buffer, indexRead, buffer.Length) работи по следния начин - чете толкова байта, колкото да напълни буфера от indexRead до buffer.Length индекса. Затова indexRead не трябва да го увеличаваш, той винаги трябва да е 0, понеже искаш да пълниш буфера от началото до края.
Също така за всеки part трябва да си създаваш отделен изходен поток (т.е. отделен файл). В момента извършваш обикновено копие.
Много благодаря, Наско :)
Успях да подкарам Split метода с помощта ти, след това направих и Assemble метода, и на пръв поглед работи, но въпреки че събрания обратно файл е със абсолютно същия размер като оригиналния, не е негово точно копие. Позвам 7-мегабайтова картинка и в резултата виждам че първата част пиксели си е на място, а след нея е долепена още една, която не е втората, и всичко останало са сиви пиксели.
Сега не мога да разбера дали при рязането на файла нещо не е ок, или при сглобяването, понеже не мога да прегледам частите по отделно и да преценя здрави ли са.
Това е кода: http://pastebin.com/qJ3gSJtK
Мисля, че и аз имам проблем с това, че чета целия файл и го зареждам в РАМ, но не се сещам как мога да го зареждам помалко и дали трябва да се ползва Flush ?
Ето кода . Надявам някой да удари рамо:)
p.s. Добавих в кода и брояч на байтовете и завъртях цикъл, за да избегна това зареждане в RAM. Дали ще работи?
Здравей Галя, виждам че при разделянето на файла използваш буфер с размер 4к байта, което е правилно. При събирането обратно мисля че трябва да ползваш същия буфер, а не такъв с размер на оригиналния файл. Би трябвало с FileMode.Append да се записва във файла последователно на парчета и в такъв случай размера на буфера може да се променя и това не би трябвало да влияе на крайния резултат.
@malkstor - алгоритъмът ти е правилен, проблемът идва от взимането да отделните парчета. Понеже parts ти е 10, Directory.GetFiles() ти връща файловете в реда Part-1, Part-10, Part-2, Part-3 и т.н., заради вградено сортиране на операционната система. И ти ги прочиташ в този ред и картинката се чупи. Дебъгни и виж как ти влизат в списъка. По скоро си ги пъхай ръчно в списък, за да си сигурен, че редът се запазва.
@GalyaGeorgieva - просто сложи размер на буфера от 4096. В момента ти е дължината на файла * брой парчета, което е повече от размера на самия файл.
byte[] buffer = new byte[4096];
while (true)
{
int readBytesCount = sourceStream.Read(buffer, 0, buffer.Length);
if (readBytesCount == 0)
break;
destinationStream.Write(buffer, 0, readBytesCount);
}
Горният код чете по 4кб от един поток, след което ги записва в друг, докато има прочетени байтове. И така във всеки един момент програмата ти има 4кб RAM задалени, което е за предпочитане отколкото да зареждаш целия файл наведнъж.
А при метода Slice как може да се направи?
ако заместя SizeofEachFile с 4096 - резултатът е "нацепени" файлове, но първия съдържа цялата информация, а другите са празни
int bytesRead = 0;
byte[] buffer = new byte[SizeofEachFile];
if ((bytesRead = originFile.Read(buffer, 0, SizeofEachFile)) > 0)
{
outputFile.Write(buffer, 0, bytesRead);
}
Имам следният въпрос обаче, ако работим с малки файлове, нека кажем че имаме 15кб картинка която трябва да я разделим на 3 файла - с буфер 4096 това, ще направи част 1 - 8192 част 2 - 8192 и част 3 - 0, това предполагам е по добре от гледна точка боравене с windows, но ще се зачита ли за коректно slice-ване? С големи файлове не е проблем, но за малки може да получим няколко части даже с големина 0.
Много благодаря Наско, всичко работи на 6 вече, никога нямаше да се сетя че това е причината!
В случай че някой друг има същия проблем и се чуди как да го оправи - супер лесно е:
string destinationFileName = string.Format("Part-{0}", (part + 1).ToString("D3")) + extension;
ако ще делите на до 999 части.
@GalyaGeorgieva - При Slice просто въртиш един цикъл, като пазиш докъде си стигнала и за всяко парче отваряш поток към нов файл. Да кажем имаш файл с 500 000 байта. За байтовете 0...9999 отваряш поток и ги пренасяш в един файл, за 10 000...20 000 правиш същото в друг файл, и т.н.
@Innos - да, прав си, при файлове по-малки от буфер 4096 ще има проблем, но пък принципно нацепването на файлове се ползва, когато са големи и искаш да ги пренесеш на малка флашка да кажеш.
@malkstor - дебъгвай, и двата пъти с едно F5 се разбира къде бъркаш :)
И аз ударих на камък с тези headers в началото на филовете. Пробвах да копирам началото на файла и да го презаписвам на всяка отделна част, но пак не стана. Пробвах с размер на header от 5 до 5 * 4096 bytes. Може ли въобще да се направят такива работещи части от .mp4 с FileStream?
До тук съм го докарал:
https://pastebin.com/sN1Diu9p