Loading...
Elena123456 avatar Elena123456 235 Точки

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 4625 Точки
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 235 Точки

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

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

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

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

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

Поздрави!

1
MartinBG avatar MartinBG 4625 Точки

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

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

1
Elena123456 avatar Elena123456 235 Точки

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

На лекция ни е показано това решение за разцепването на един файл на четири еднакви парчета- 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 4625 Точки

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

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

 

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

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

Ами с 3?

А при 0?

 :)

 

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

2
Elena123456 avatar Elena123456 235 Точки

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

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

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

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

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

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

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

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