Професионална програма
Loading...
Elena123456 avatar Elena123456 199 Точки

4. Copy Binary File- solution with buffer and another with CopyTo

Здравейте,

задачата е  № 4 от тук- https://softuni.bg/trainings/resources/officedocument/52728/streams-files-and-directories-exercise-csharp-advanced-september-2020/3007

Ще бъда много благодарна, ако някой погледне двете ми решения и потвърди дали са абсолютно взаимозаменяеми- едното е с използването на буфер, а другото е директно с копиране.

Решението без буфер- https://pastebin.com/HMt1aNva

Решението с буфер- https://pastebin.com/K9zB1nX6

На пръв поглед резултата и при двете е еднакъв. Абсолютно заменяеми ли са и има ли случай, в който е за предпочитане да използвам решението, което е с буфер?

 

Тагове:
0
C# Advanced
MartinBG avatar MartinBG 3828 Точки
Best Answer

В решението с буфер има бъг на ред №22:

writer.Write(buffer, 0, buffer.Length);

Трябва да е:

writer.Write(buffer, 0, bytesRead);

Може да се запише и така:

int bytesRead;

while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
{
   writer.Write(buffer, 0, bytesRead);
}

Иначе, двете решения са функционално еквивалентни.

Основната причина да се използва буфериране е, че получаването или изпращането на (примерно) 1000 байта не е много по-бавно от това на 1 байт (т.е. 1000 операции по 1 байт ще са много пъти по-бавни от 1 операция с 1000 байта).

 

 

Сега погледнах спецификацията на CopyTo метода и изглежда, че и той използва буфериране. По подразбиране размерът на буфера е 81920 байта, но методът има овърлоуднат вариант, при който размерът на буфера може да бъде указан изрично.

При наличието на подобен помощен метод, създаването на собствен буфер и използването на Read + Write методите за копиране изглежда излишно и е оправдано само ако искаме да модифицираме или да анализираме прочетените данни, преди да ги запишем на новото място.

 

2
18/01/2021 01:34:48
Elena123456 avatar Elena123456 199 Точки

Благодаря за отговора и за  открития бъг. smiley

Досега не успявах да разбера задачите с използването на буфер и докато се опитвах да избегна използването му се натъкнах случайно на "CopyTo". Предполагам, че ще свърши работа дори и при разцепването на файл на еднакви парчета, като можем да му променяме размера на буфера.

След като видях вашия запис с използването на буфер, вече разбрах какво се казва на програмата- "чети с размера на буфера, но ако не можеш накрая да четеш с размера на буфера, чети колкото байтове остават. Винаги, колкото байтове прочетеш от единия файл, запиши ги в другия файл. И няма логика в другия файл да записваме bufer.length, защото съвсем накрая може да са прочетени доста по-малко байтове".

Като дете съм виждала грамофон и четенето с буфер ми напомня на него- главата му се движи по плочата с една и съща скорост (с един и същи буфер) и накрая чете колкото остава преди да свърши песента. Така трябва да е и тук, нали? Но за жалост и една песен на грамофон не си спомням. smiley

Още веднъж много благодаря за разяснението.

Поздрави!

1
MartinBG avatar MartinBG 3828 Точки

Да, CopyTo е по-добрият вариант за копиране на данни от един поток/файл в друг, защото премахва нуждата от ръчно менажиране на буфера.

Да, в буфера се четат колкото се може повече байтове (до размера на буфера или колкото има останали във входящия поток) и  като резултат се връща размера на реално прочетените байтове.

1
Elena123456 avatar Elena123456 199 Точки

Извинявам се много, но имам само още едно питане отностно работата с буфери, преди да ги завърша.

На лекция ни е показано това решение за разцепването на един файл на четири еднакви парчета- https://pastebin.com/ykAJFdFj , но виждам, че отново при писането в останалите четири файла е използвана дължината на буфера( buffer.Length ), а не прочетените байтове(bufferRead). Допълнително има една проверка:

  • if (bytesRead < buffer.Length)

                {

                    buffer = buffer.Take(bytesRead).ToArray();

                }

  Въпроса ми е дали е едно и също, ако махна горната проверка и коригирам последния ред- винаги да се изписват точно прочетените байтове във всеки един от четирите файла- " currentPartStream.Write(buffer, 0, bufferRead) ", вместо-   "currentPartStream.Write(buffer, 0, buffer.Length) ". Това решение би ли дало бъг, който не е явен в тази задача? Питам понеже няма Judge за задачата и ми е малко трудно все още да я тествам.

0
20/01/2021 00:20:07
MartinBG avatar MartinBG 3828 Точки

Да, по-добре ще е ако се махне междинната проверка и се използват реално прочетените байтове при записа.

Тази промяна няма да внесе нови бъгове в програмата.

 

Иначе, задачата е странна като условие.

Какво трябва да е поведението при файл с 5 байта?

Ами с 3?

А при 0?

 :)

 

Решението най-вероятно ще има проблеми при много голям файл, защото ще се опита да създаде твърде голям буфер.

2
Elena123456 avatar Elena123456 199 Точки

Благодаря за отговора! smiley

Май тази задача е  с цел да видим използването на буфер, без реално приложение в практиката.

Ако инпута е 5 байта и винаги закръгляне байтовете нагоре, като ги взимаме, няма да имаме  по 2 байта и за четирите файла. Предпоследния файл ще е с 1 байт, а последния с 0. Осъзнавам, че в случая  най-малко 8 байта трябва да имаме за да се случи разцепването- примерно по един чар във всеки файл.

Или за всички други инпути- да са кратни на 4 за да е еднакво разцепването.

Ако са 4 байта не се сещам за реална причина защо бихме искали да разцепим файла на 4 файла от по един байт- но не изключвам да има такава.

Ще се радвам, ако скоро учим как да използваме и  Network stream.

 Поздрави и още веднъж благодаря! 

1