Софтуерно Инженерство
Loading...
NikolayUzunov avatar NikolayUzunov 7 Точки

[Homework]AdvancedC# - Files and Streams

Домашното не е качено . Може ли да го качите ? Друг път се качват презентацията, демата, домашното първи след това и видеото .

Евентуално темата може да се ползва и за споделяне на решения по домашното . 

Тагове:
3
C# Advanced
KatyaMarincheva avatar KatyaMarincheva 572 Точки

И аз имам въпрос за 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-ва нормално.

Може ли нещо да се подобри или с някои типове инпут файлове създадените парчета ще си останат дефектни и неизползваеми?

Ето кода  - предварително благодаря за всякакви идеи :)

-1
22/05/2015 10:50:27
a_rusenov avatar a_rusenov 1103 Точки

Само първото парче можеш да отвориш, понеже всеки бинарен файл съдържа в началото си няколко байта описание за себе си. Без тях програмата, която го отваря, няма как да знае какво чете (mp3, avi, png и т.н.). Нормално е, когато нарежеш един файл на няколко части, хедърите му да останат само в първата част и затова плейърът разпознава само нея като валиден .avi файл.

Относно кода:

  1. Assemble не работи правилно, защото никъде не прочиташ от входния поток нищо (просто инициализираш празен байт масив и го записваш в изходния поток). Ползвай partSource.Read(...).
  2. Навсякъде четеш целия файл наведнъж - това е ок за малки файлове, но става проблем при големи (да кажем 1 гб.), защото зареждаш всичко в РАМ и рискуваш OutOfMemoryException. По-правилно е да имаш буфер от 4096 байта (препоръчелна дължина при работа с Уиндоус) и малко по малко да четеш от входния поток, същевременно записвайки в изходния.
  3. SafeFileHandle ImagePath най-долу не ти трябва :)
3
malkstor avatar malkstor 348 Точки

Аз зациклих на това: http://pastebin.com/yhQqMccP

Не мога да разбера защо ми дава Exception, че параметрите в четенето indexRead и buffer.Length са невалидни.

0
22/05/2015 10:20:39
a_rusenov avatar a_rusenov 1103 Точки

.Read(buffer, indexRead, buffer.Length) работи по следния начин - чете толкова байта, колкото да напълни буфера от indexRead до buffer.Length индекса. Затова indexRead не трябва да го увеличаваш, той винаги трябва да е 0, понеже искаш да пълниш буфера от началото до края.

Също така за всеки part трябва да си създаваш отделен изходен поток (т.е. отделен файл). В момента извършваш обикновено копие.

3
malkstor avatar malkstor 348 Точки

Много благодаря, Наско :)

Успях да подкарам Split метода с помощта ти, след това направих и Assemble метода, и на пръв поглед работи, но въпреки че събрания обратно файл е със абсолютно същия размер като оригиналния, не е негово точно копие. Позвам 7-мегабайтова картинка и в резултата виждам че първата част пиксели си е на място, а след нея е долепена още една, която не е втората, и всичко останало са сиви пиксели.

Сега не мога да разбера дали при рязането на файла нещо не е ок, или при сглобяването, понеже не мога да прегледам частите по отделно и да преценя здрави ли са.

Това е кода: http://pastebin.com/qJ3gSJtK

1
22/05/2015 13:46:44
GalyaGeorgieva avatar GalyaGeorgieva 88 Точки

Мисля, че и аз имам проблем с това, че чета целия файл и го зареждам в РАМ, но не се сещам как мога да го зареждам помалко и дали трябва да се ползва Flush ?
Ето кода . Надявам някой да удари рамо:)

p.s. Добавих в кода и брояч на байтовете и завъртях цикъл, за да избегна това зареждане в RAM. Дали ще работи?

0
22/05/2015 14:28:34
malkstor avatar malkstor 348 Точки

Здравей Галя, виждам че при разделянето на файла използваш буфер с размер 4к байта, което е правилно. При събирането обратно мисля че трябва да ползваш същия буфер, а не такъв с размер на оригиналния файл. Би трябвало с FileMode.Append да се записва във файла последователно на парчета и в такъв случай размера на буфера може да се променя и това не би трябвало да влияе на крайния резултат.

0
22/05/2015 14:39:06
a_rusenov avatar a_rusenov 1103 Точки

@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 задалени, което е за предпочитане отколкото да зареждаш целия файл наведнъж.

2
22/05/2015 14:44:35
GalyaGeorgieva avatar GalyaGeorgieva 88 Точки

А при метода Slice как може да се направи?
ако заместя SizeofEachFile с 4096 - резултатът е "нацепени" файлове, но първия съдържа цялата информация, а другите са празни

                        int bytesRead = 0;
                        byte[] buffer = new byte[SizeofEachFile];

                        if ((bytesRead = originFile.Read(buffer, 0, SizeofEachFile)) > 0)
                        {
                            outputFile.Write(buffer, 0, bytesRead);
                        }

0
Innos avatar Innos SoftUni Team 419 Точки

Имам следният въпрос обаче, ако работим с малки файлове, нека кажем че имаме 15кб картинка която трябва да я разделим на 3 файла - с буфер 4096 това, ще направи част 1 - 8192 част 2 - 8192 и част 3 - 0, това предполагам е по добре от гледна точка боравене с windows, но ще се зачита ли за коректно slice-ване? С големи файлове не е проблем, но за малки може да получим няколко части даже с големина 0.

1
22/05/2015 16:08:40
malkstor avatar malkstor 348 Точки

Много благодаря Наско, всичко работи на 6 вече, никога нямаше да се сетя че това е причината!

В случай че някой друг има същия проблем и се чуди как да го оправи - супер лесно е:

string destinationFileName = string.Format("Part-{0}", (part + 1).ToString("D3")) + extension;

ако ще делите на до 999 части.

1
a_rusenov avatar a_rusenov 1103 Точки

@GalyaGeorgieva - При Slice просто въртиш един цикъл, като пазиш докъде си стигнала и за всяко парче отваряш поток към нов файл. Да кажем имаш файл с 500 000 байта. За байтовете 0...9999 отваряш поток и ги пренасяш в един файл, за 10 000...20 000 правиш същото в друг файл, и т.н.

@Innos - да, прав си, при файлове по-малки от буфер 4096 ще има проблем, но пък принципно нацепването на файлове се ползва, когато са големи и искаш да ги пренесеш на малка флашка да кажеш.

@malkstor - дебъгвай, и двата пъти с едно F5 се разбира къде бъркаш :)

2
AleksanderKostadinov avatar AleksanderKostadinov 12 Точки

И аз ударих на камък с тези headers в началото на филовете. Пробвах да копирам началото на файла и да го презаписвам на всяка отделна част, но пак не стана. Пробвах с размер на header  от 5 до 5 * 4096 bytes. Може ли въобще да се направят такива работещи части от .mp4 с FileStream?

До тук съм го докарал:

https://pastebin.com/sN1Diu9p

 

0