передача побайтно
у меня к вам небольшой вопрос.
Имеется файл в сети возможен ли такой способ его копирования:
по действиям:
1) узнаем размер файла
2) присваеваем каждому байту свой порядковый номер
3) создаем два потока
4) каждый поток копирует свои номера байт из удаленного файла
Возможно ли организовать такую работу копирования?
Подскажите в какую сторону копать пожалуйста...
А в принципе,кажется seek и read тебе в помощь.
2) присваеваем каждому байту свой порядковый номер
Вот тут хотелось бы по-подробнее узнать, как автор себе это представляет.
Хм. Если это то, что я понял, то копирование номеров байт (!) займет раз так в N больше времени, чем копирование файла. Вообще попахивает бредом и выглядит так же...
Хм. Если это то, что я понял, то копирование номеров байт (!) займет раз так в N больше времени, чем копирование файла. Вообще попахивает бредом и выглядит так же...
Это он мультиплексированием хотел заняться. Такой подход используют "качалки" - тянут файл по разным смещениям, как известно, способ может лучше использовать пропускную способность канала.
TFileStream * Stream2 = new TFileStream("C:\\Restored.exe",fmCreate|Sysutils::fmOpenRead);
__try
{
Stream2->CopyFrom(Stream1,Stream1->Seek(Stream1->Size/2,soFromBeginning));
}
__finally{
Stream2->Free();
}
Stream1->Free();
Имеется поток Stream1... Но задача в следующем
всего должно быть 4 потока, и каждый из них должен копировать по
1\4 части размера файла... причем каждый поток свою часть файла...
немогу сообразить как это реализовать даже методом Seek(); этого недобиться.... а очень надо...
_______________________________________________
Не пытайтесь придумывать разные глупости о том: "Че это он там пытается реализовать?"... Отвечу так надо...
Автору: если использовать для файла такое:
FILE* f;
f = fopen(name,"rb");
То можно fseek'ом выставлять маркер и читать из нужных мест. Но я сомневаюсь, что на деле это можно будет осуществить, т.к. система поставит блок на файл и кинет ошибку, если к нему обратятся 2 потока сразу.
Но если найдёшь способ - не забудь отписать
Автору: если использовать для файла такое:
FILE* f;
f = fopen(name,"rb");
То можно fseek'ом выставлять маркер и читать из нужных мест. Но я сомневаюсь, что на деле это можно будет осуществить, т.к. система поставит блок на файл и кинет ошибку, если к нему обратятся 2 потока сразу.
Но если найдёшь способ - не забудь отписать
Да я с такой проблемой столкнулся... уже...
я немного переделал текст, и решил брать из потока в котором у нас искомый файл( тоесть тот который на надо скопировать)...
до этого я использовал метод CopyFrom(); но оно не подошло, именно по той причине что вы указали, поэтому я рышил, помещать все содержимое в буфер, но столкнулся с другой проблемой... Для примера я одним потоком копировал содержимое файла начиная от 0 байт до 72 байта, а вторым копировал от 72 до 144 (я для примера заранее узнал размер файла, исходя из чего поделил его пополам) , в результате проблема в том как эти данные сохранить в один и тот же файл, получается токо половина от 0 байт до 72 байт а следующие 72 байта при записи из потока в файл вылетает ошибка Stream Read Error .
Вот код:
TFileStream * Stream2 = new TFileStream("C:\\Restored.txt",fmCreate|Sysutils::fmOpenWrite);
TFileStream * Stream3 = new TFileStream("C:\\Restored2.txt",fmCreate|Sysutils::fmOpenWrite);
char buf[1024];
char buf2[1024];
Stream1->Seek(72,0);
Stream1->ReadBuffer(buf,72);
Stream1->Seek(72,71);
Stream1->ReadBuffer(buf2,72);
Stream2->WriteBuffer(buf,72);
Stream3->WriteBuffer(buf2,144);
Stream2->Free();
Stream3->Free();
Stream1->Free();
Вот тут уменя все какбы работает, то есть содержимое файла Restored.txt
забирает первую от начала половину Stream2(записывается в C:\Restored.txt), а вторую от середины забирает Stream3 (записывается в C:\Restored2.txt), и опять же в один файл незаписывается, ненаю что делать..
Может кто подскажет...
А насчет FILE*f;
Я незнаю ничего о маркерах я токо знаю что приведенный вами метод это типизированная работа с файлами, в ней мне кажется меньше возможности чем в нетипизировнной (TFileStream)...
Ну если вашим методом решается такая проблема, то будьте добры поделитесь...
Имхо, тут о типизированности файлов говорить не приходится. Я тоже читаю байтами. Просто FILE* это С, а вот такие потоки, это уже что-то плюсовое, поэтому мне похуже знакомо.
Маркером я назвал указатель на позицию в файле, откуда читаем/пишем. Ну т.е. seek в твоём коде.
Если не сложно, прокомментируй строки Stream1->Seek(72,71); и Stream3->WriteBuffer(buf2,144);
Мне как-то неочевидны параметры.
И не совсем понятно, что же в итоге хотим получить, т.к. в этом коде не вижу потоков.
Вообще, логика должна быть где-то такой:
Узнаём размер файла.
Делим размер на количество потоков (пусть 2). Получаем сколько байт на поток приходится (пусть M)
Потоки нумеруем с 0.
Для каждого потока устанавливаем маркер на (начало + M*№потока). Читаем М байт в заранее отведённый массив. Но располагаем данные в массиве не абы как, а опять же, начиная с (начало + М*№потока). ТО есть первый поток читает первые 72 байта файла и пишет их в буффер на позиции 0-71. Второй поток читает вторую часть файла и пишет на позиции 72-143. В итоге весь файл лежит в массиве.
Теперь массив надо слить в новый файл. Это либо легко делается одним потоком, либо тоже хотим распараллелить. Но тут опять же сложность. Мы не сможем для 2ого и дальнейших потоков указать маркеру место. Второй должен писать с 73 байта. но seek не позволит встатть на 73, т.к. пока первый поток не отработал, то файл не имеет такого размера. Тут я вижу выход в заведомом создании пустого фейкового файла нужного размера просто из нулей.
Всё. но остались 2 проблемы, решения которых я придумать не могу. Представим ситуацию, что первый поток при чтении исходного файла делает seek на начало. Тут происходит прерывание и второй поток делает seek на 73ий байт. Второй поток читает свою половину файла и пишет в нужные места массива. тут снова прерывание и первый поток, считая что маркер seek на начале, читает свои 72 байта. Только вот на самом деле seek уже на конце...
И если решить проблему мьютексами, то это убьёт все плюсы многопоточности
Имхо, тут о типизированности файлов говорить не приходится. Я тоже читаю байтами. Просто FILE* это С, а вот такие потоки, это уже что-то плюсовое, поэтому мне похуже знакомо.
Маркером я назвал указатель на позицию в файле, откуда читаем/пишем. Ну т.е. seek в твоём коде.
Если не сложно, прокомментируй строки Stream1->Seek(72,71); и Stream3->WriteBuffer(buf2,144);
Мне как-то неочевидны параметры.
И не совсем понятно, что же в итоге хотим получить, т.к. в этом коде не вижу потоков.
Вообще, логика должна быть где-то такой:
Узнаём размер файла.
Делим размер на количество потоков (пусть 2). Получаем сколько байт на поток приходится (пусть M)
Потоки нумеруем с 0.
Для каждого потока устанавливаем маркер на (начало + M*№потока). Читаем М байт в заранее отведённый массив. Но располагаем данные в массиве не абы как, а опять же, начиная с (начало + М*№потока). ТО есть первый поток читает первые 72 байта файла и пишет их в буффер на позиции 0-71. Второй поток читает вторую часть файла и пишет на позиции 72-143. В итоге весь файл лежит в массиве.
Теперь массив надо слить в новый файл. Это либо легко делается одним потоком, либо тоже хотим распараллелить. Но тут опять же сложность. Мы не сможем для 2ого и дальнейших потоков указать маркеру место. Второй должен писать с 73 байта. но seek не позволит встатть на 73, т.к. пока первый поток не отработал, то файл не имеет такого размера. Тут я вижу выход в заведомом создании пустого фейкового файла нужного размера просто из нулей.
Всё. но остались 2 проблемы, решения которых я придумать не могу. Представим ситуацию, что первый поток при чтении исходного файла делает seek на начало. Тут происходит прерывание и второй поток делает seek на 73ий байт. Второй поток читает свою половину файла и пишет в нужные места массива. тут снова прерывание и первый поток, считая что маркер seek на начале, читает свои 72 байта. Только вот на самом деле seek уже на конце...
И если решить проблему мьютексами, то это убьёт все плюсы многопоточности
Вот сматри размер файла хранится в Stream1->Size; (Это и есть размер файла в байтах);
Stream1->seek(x,y) - где x - это количество считываемых байт, а y - это начало отсчета, то есть с какого байта начинать считывать, ну тот же самы маркер как ты сказал...
Stream1->ReadBuffer(buf,72);
Это мы считываем в буфер содержимое потока Stream1 данные от 0 до 72 байта, а
Stream2->WriteBuffer(buf,72);
Это мы записываем содержимое буфера buf в новый поток для далнейшего сохранения на жесткий диск...
Проблема в том что, раздельно считанные данные неполучается обьединить в той же последовательности , да и не токо в той же последовательности вообще никак неполучается их обьединить...
То есть как у меня в коде написано я записал в поток Stream2 - содержимое копируемого файла с 0 по 72 байт, а в поток Stream3 - тоже содержимое копируемого файла токо с 72 по 144 байт ( общий размер файла 144 байта)...
И тут возникла проблема, как эти потоки сохранить в один и тот же файл...
Удается сохранить токо один поток, а не оба, то есть либо Stream2 либо Stream3, при попытки записать второй поток вылетает ошибка Stream read error... но при сохранение потоков в разные файлы тоесть Stream2 сохраняю в Restored.txt а Stream3 сохраняю в Restored2.txt в обоих файлах содержимое соответствует половине начального файла ( тот что загружен в Stream1)
Впринцепе проблема токо в этом как сохранить два потока в один файл...
Ну как бы содержимое потоков еще и в буферах Buf, и buf2 Хранится пробовал в поток добавить сначало buf потом buf2 но чет нече не получилось...
Вот рабочий код все работает...
#include <fstream>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TFileStream * Stream1 = new TFileStream("C:\\123\\restored.txt",Sysutils::fmOpenRead);
TFileStream * Stream2 = new TFileStream("C:\\Restored.txt",fmCreate|Sysutils::fmOpenWrite);
char buf[1024];
char buf2[1024];
////////////////////////////////////////////////////////////////////////////
Stream1->Seek(72,145);
Stream1->ReadBuffer(buf,72);
Stream2->WriteBuffer(buf,72);
Stream1->Free();
Stream2->Free();
///////////////////////////////////////////////////////////////////////////
TFileStream * Stream4 = new TFileStream("C:\\123\\restored.txt",Sysutils::fmOpenRead);
TFileStream * Stream3 = new TFileStream("C:\\Restored.txt",Sysutils::fmOpenWrite);
Stream4->Seek(72,0);
Stream4->ReadBuffer(buf2,72);
Stream3->Seek(72,0);
Stream3->WriteBuffer(buf2,72);
Stream3->Free();
Stream4->Free();
}
Но теперь другая проблема, возможноли одновременное выполнение считывания байт обоими потоками?
#include <fstream>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TFileStream * Stream1 = new TFileStream("C:\\123\\Restored.txt",Sysutils::fmOpenRead);
TFileStream * Stream2 = new TFileStream("C:\\Restored.txt",fmCreate|Sysutils::fmOpenWrite);
char buf[1024];
char buf2[1024];
////////////////////////////////////////////////////////////////////////////
Stream1->Seek(Stream1->Size/2,Stream1->Size+1);
Stream1->ReadBuffer(buf,Stream1->Size/2);
Stream2->WriteBuffer(buf,Stream1->Size/2);
Stream1->Free();
Stream2->Free();
///////////////////////////////////////////////////////////////////////////
TFileStream * Stream4 = new TFileStream("C:\\123\\restored.txt",Sysutils::fmOpenRead);
TFileStream * Stream3 = new TFileStream("C:\\Restored.txt",Sysutils::fmOpenWrite);
Stream4->Seek(Stream4->Size/2,0);
Stream4->ReadBuffer(buf2,Stream4->Size/2);
Stream3->Seek(Stream4->Size/2,0);
Stream3->WriteBuffer(buf2,Stream4->Size/2);
Stream3->Free();
Stream4->Free();
}
Столкнулся с еще одной проблемой, при выполнение копирования файла размером до 1000 байт все работает отлично, но при копирование большего размера файла, вылетает ошибка чтения потока (Stream read error). Пробовал размер буффера увеличить но почемуто при налаче выполнения выше указанного кода при увеличение размера буфера, программа закрывается...
никогда так не делай
для этого есть - delete;
DWORD WINAPI func(LPVOID param) { тут второй поток читает вторую часть файла}
в первом потоке прям в начале мэйна запустить второй
HANDLE th2 = CreateThread(..,&func,..);
а тут уже самому читать первую часть файла
Проблема буфера в том, что ты создаёшь их на 1024 байта только char buf[1024];
DWORD WINAPI func(LPVOID param) { тут второй поток читает вторую часть файла}
в первом потоке прям в начале мэйна запустить второй
HANDLE th2 = CreateThread(..,&func,..);
а тут уже самому читать первую часть файла
Проблема буфера в том, что ты создаёшь их на 1024 байта только char buf[1024];
А можеш поподробней обьяснить про метод CreateThread(..,&func,..);
Как я понял он при выполнение процесса копирования в токок первой половины файла, запустит копирование в поток вторую полофину файла...
А про буфер, я же делал например char buf[5000000] но при начале
чтения в поток прога просто закрывалась, причем безо всяких на то сообщений.
Увеличиваю буфер до 1мб... (char buf[1000000];)
При начале чтения файла в буфер программа просто закрывается полностью...
Но при чтение в буфер файла с меньшим размером все работает нормально... в чем проблема немогу понять... подскажите пожалусто...
#include <fstream>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TFileStream * Stream1 = new TFileStream("C:\\123\\1.txt",Sysutils::fmOpenRead); //Создаем поток Stream1
TFileStream * Stream2 = new TFileStream("C:\\Restored2.exe",fmCreate|Sysutils::fmOpenWrite); //Создаем поток Stream2
char buf[1000000]; //Указываем буфер
////////////////////////////////////////////////////////////////////////////
Stream1->Seek(Stream1->Size,Stream1->Size+1); //Устанавливаем маркер считывания файла (Поток->Seek(Общий считываемый размер,Начало считывания)
Stream1->ReadBuffer(buf,Stream1->Size); //Считываем данные в буфер buf
Stream2->WriteBuffer(buf,Stream1->Size); //записываем данные из буфера buf в поток Stream2
Stream1->Free(); //Закрываем поток Stream1
Stream2->Free(); //Закрываем поток Stream2
}
данные из файла вроде как правильно считываются потому что в коннечном итоге мы имеем аналогичный файл, из которого считывали данные... но по окончание считывания почему все равно вылетает ошибка Stream read error...
Может кто подскажет из-за чего?
#include <fstream>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TFileStream * Stream1 = new TFileStream("C:\\123\\r.txt",Sysutils::fmOpenRead);
TFileStream * Stream2 = new TFileStream("C:\\Restored2.mp3",fmCreate|Sysutils::fmOpenWrite);
int i;
char buf[1024];
__try
{
for (i = 0; i < Stream1->Size; i++)
{
if(buf=="80")
{
buf==0;
i=i-1;
}
else
{
Stream1->ReadBuffer(buf,80);
Stream2->WriteBuffer(buf,80);
Label1->Caption=i;
}
if (i==Stream1->Size)
{
Stream2->Free();
Stream1->Free();
}
{
}
}
}
__finally
{
Stream2->Free();
}
Stream1->Free();
}
Есть другой вопрос...
Вновь воспользуюсь мои примером, который я указывал выше...
проблема в том что, например потоки Stream1 и Stream2 уже выполняют считывание в программе, и тут новое обращение на считывание нового файла, тоесть нужно чтобы программа как то (даж незнаю как это назвать) сама создала с рандомным названием новых потоков для выполнения новой задачи считывания байт...
Возможно ли вообще такое? И если кто знает в какую сторону капать?
За помощ я обязательно добавлю вес репутации...
Возможно ли вообще такое? И если кто знает в какую сторону капать?
массив потоков?
stream[0] = new TFileStream(...)
Запрос - это, видимо, вызов конкретной функции из потока. Тогда если сделать FileStream локальными внутри функции, то это решает проблему. Т.е. при каждом вызове Stream1, stream2 свои.
зы: а проблему с многопоточным чтением/записью как решил?
TFileStream * Stream2 = new TFileStream(Output,fmCreate|Sysutils::fmOpenWrite);
char buf[1024];
__try
{
for (i = 0; i < Stream1->Size/32; i++) {
Stream1->Seek(i*32,Stream1->Size);
Stream1->ReadBuffer(buf,32);
Stream2->WriteBuffer(buf,32);
}
}
__finally
{
Stream2->Free();
}
Stream1->Free();
Попробую правильно сформулировать...
Выше указанный код считывает данные из файла указанного в потоке Stream1 переменной Patch(путь к файлу), в Stream2 и сохраняет в Output(путь к файлу), проблема в том что, предположим действия по коду...
по условию for цикл будет идти столько раз скольки равняется размер файла деленного на 32...
Для примера у нас имеется файл размером 100 байт...
то после разделения его на 32 получится 3,1.
но проблема в том что из этих 100 байт выполнится(скопируется, считается) токо 96 байт...
Я так понимаю что это из за того что i является переменной типа int, но я указывал и i типа float и тем не менее была таже проблема...
В чем моя ошибка подскажите пожалуйста знающие люди...
Но почему, если размер файла 100 байт, он и после даже неоднократного копирования будет оставаться равным 100 байт...
Мне кажется просто в моем коде считывание файла побайтно организовано неправильно, ведь цикл for несможет выполниться например 3,5 раза а токо 3.Поэтому остаток равный меньшему такту считывания за цикл( у меня это 32) будет оставаться не считанным. А как заставить этот код считать все до конца. Конечно можно установить такт считывания равным 1 то тогда само считывание данных из файла очень долго длится. Я вот вообще его делал 1кб, скорость копирования при этом была быстрее чем тот же файл копировала Винда.
Люди подскажите что не так в моем коде...
получаешь сколько байт не влезло в копирование циклом. (в твоём случае 4)
соответственно, ставишь маркер чтения за 4 байта до окончания файла и читаешь эти 4 байта.
Только весь этот код - однопоточное чтение файла, просто в несколько приёмов
хотел доработать этот пример доконца...
ща попробую... твое предложение... по выходу из ситуации...
Только весь этот код - однопоточное чтение файла, просто в несколько приёмов
Для одновременного выполнения одной и тойже функцией тебе нужно добавить в проект Thread Object, внем описать функцию считывания потока.
Я столкнулся с еще одной проблемой...
При создание потока нужно сделать открытие файла не в монопольном режиме.. Посколку из-за етого второй паралельно запущенный поток не может получить доступ к файлу...
Я знаю что в функции TFileStream есть флаги которае указывают на способ открытия файла - fmOpenRead - открыть файл для чтения, fmOpenWrite - открыть файл для записи, fmCreate - создать файл..
я знаю это не все флаги, должен быть флаг открывающий файл не в монопольном режиме, но какой чета пока немогу найти...
кто знает подскажите пожалуста...
Я перепробовал все флаги... толку нет... выполняется токо один паток, а второй пишет нет доступа к файлу, или файл занят другим процессом...
Я думаю дело в методе TFileStream наверное надо поискать какой то другой метод который будет обращаться к файлу не в монопольном режиме....
Кто знает подскажите пожалуйста..
разве не работает?
разве не работает?
Я так пробовал, нет так неработает...
Вообще С.Бобровский пишет ...
Пока программа не прекратит обработку файла, его содержимое в определенный момент времени невозможно предсказать - информация может постоянно модифицироваться. Когда файл открывается на чтение, его внутренняя структура неизменяется. Поэтому несколько программ могут открыть файл на чтение. Другие варианты открытия файла подразумевают монопольную работу одной программы с ним.
Так вот как он пишет я так понял ето просто fmOpenRead, но
все равно токо один поток может работать с этим файлом...
Кстати:
static const Shortint fmShareCompat = 0x0;
так что...
Кстати:
static const Shortint fmShareCompat = 0x0;
так что...
Тоже неподошло пишет Stream read error...(((
А у вас разве этот флаг сработал?
Кстати:
static const Shortint fmShareCompat = 0x0;
так что...
Ссори, Все работает, вчера вчера чет не то делал...))))
То можно fseek'ом выставлять маркер и читать из нужных мест. Но я сомневаюсь, что на деле это можно будет осуществить, т.к. система поставит блок на файл и кинет ошибку, если к нему обратятся 2 потока сразу.
"Сразу" два потока обратиться к файлу не могут. Оба потока пренадлежат одной ОС (и одному приложению), значит. Вы можете передавать потоку при его создании дескриптор файла и смещение. И потоки будут по-очереди читать и передавать!
Так что stdio.h:fseek или io.h:seek Вам в руки! Если хотите сделать потоки независимыми, можете открыть файл с Share Access - io.h:sopen (или подобные) в помощь.
Так что stdio.h:fseek или io.h:seek Вам в руки! Если хотите сделать потоки независимыми, можете открыть файл с Share Access - io.h:sopen (или подобные) в помощь.
Вы ошибаетесь... Я создал многопоточное прилошение, и использовал выше указанные флаги для открытия файла... все прекрасно работает... одновременно считывается информация 2 потоками. Первый считывает от 0 до половины байт, а второй от половины и до конца, но я использовал не seek а Position, мне показалось это удобней, чем использовать смещения seek.
Ток проблема.. оба потока одновременно считывают свою половину в свой буфер(buf1,buf2). Например в buf1 - от0 до 50байт, а в buf2 - от50 до 100 байт (весь файл 100байт). Как записатб это все в один буфер...
вот с этим проблема , пробовал сохранить каждый своим потоком но получается таким образом, что записывается токо какой то один поток, это скорее всего потому что в новый файл они записываться оба от 0 байта... и поэтому друг друга затирают...
Не понимаю,что вызвало у вас проблему
Ну или код в студию
Не понимаю,что вызвало у вас проблему
Ну или код в студию
Я так пробовал... Записываю buf1 тоесть
Fi->WriteBuffer(buf1,100);
А потом и точно так же второй буфер buf2..
Fi->WriteBuffer(buf2,100);
Обе записи выполняются паралельно, и после выполнения в файле токо половина всего файла, то есть либо содержимое buf1 ли бо buf2.
Вычитал, что для того чтобы записать информацию в файл без удаления уже имеющейся в ней записи необходимо открыть файл не на запись а на дозапись, в этом случае данные токо добавятся... но опять же вопрос каким флагом открыть файл на дозапись?
пробовал флаг fmOpenReadWrite, но происходит тоже самое, тоесть в файле, либо информация буфера buf1 ли бо buf2.
Если делать запись в файл последовательно, то последующие записи тоесть в данном примере buf2 должен открывать файл на дозапись, а первый создает файл и записывает в него первую половину информации от 0 байта до половины.