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 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
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.