Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Delphi: Общие вопросы > Сохранение нескольких файлов в одном |
Автор: pushok 13.8.2009, 10:39 |
Всем привет. Пишу программу. Столкнулся с проблемой: есть несколько файлов разного формата (текстовые, графические) нужно сохранять все эти файлы в одном для удобства транспортировки. Никогда с такой проблемой не сталкивался. Первым делом думал создавать новую папку и сохранять нужные файлы в ней, но для конечного пользователя это всеравно будет неудобно. Еще есть мысль сохранять всю нужную мне информацию в одном файле, записывая его по-байтам в определенном формате, но это как вы сами понимаете - гемор = ) Подскажите, может быть в Delphi есть какие-то предусмотренные способы или функции решения этой проблемы. Может быть в Delphi есть функции работы с архивами. Может быть эти проблемы решаются средствами WinAPI. Заранее спасибо за помощь. |
Автор: AntonN 13.8.2009, 10:50 | ||
ничуть, именно так поступаю когда нужно упаковать скины для программ или что то подобное. Если потратишь немного времени и разберешься - все будет легко и красиво ![]() дял примера небольшой класс который сохраняет несколько Tbitmap (разных размеров, битности) в один файл - http://desksoft.ru/index.php?forum=13&th=110 если приглядеться то битамп перед сохранением в общий файл выгружается в Tstream - _MBit, ну так вот грузи в этот поток все что тебе угодно, хоть EXE, хоть GIF. Только придется в заголовки добавить поле типа string куда запишется название файла ![]() |
Автор: Yanis 13.8.2009, 11:01 |
Товарищи велосипедисты, с исследовательской точки зрения можно, конечно, хранить вообще все файлы хоть в исполняемом файле. С практической же стороны, архивы ZIP очень даже доставляют в случае хранения ресурсов в одном хранилище. И да, pushok, в Delphi есть модуль для поддержки сжатия по алгоритму DEFLATE. Модуль http://ru.wikipedia.org/wiki/Zlib. Добавлено @ 11:02 http://forum.vingrad.ru/index.php?act=Search&CODE=show&searchid=86d705afc119e69a36834577f5e07488&search_in=posts&result_type=topics&flag=search&debug=&highlite=zlib&skipped= |
Автор: former 13.8.2009, 13:13 |
http://forum.vingrad.ru/forum/topic-90023.html# еще вариант. |
Автор: kemiisto 13.8.2009, 13:20 |
Yanis, ![]() http://www.delphizip.org/ есть толковый компонент для работы с Zip. Как альтернатива - компонент с говорящим названием http://www.torry.net/authorsmore.php?id=5967. ![]() |
Автор: w03zd8rc 13.8.2009, 13:43 |
собстна можно взять консольную версию винрара (ставится вместе с винраром) и паковать нужные файлы в один архив через консоль (совсем несложно в делфи) |
Автор: pushok 16.8.2009, 12:38 | ||
Ребят, пару дней разбирался - ничего не понял. Вот из какой-то ссылки (что вы давали) вытянул кусок кода по-проще. Работает хорошо, только вот понять как он работает немогу. С потоками в плохих отношениях = ) Напишите пожалуйста пояснения к некоторым строчкам.
И еще алгоритм записи и чтения в один поток двух файлов выглядит так: Запись 1. Записываем длину первого файла 2. Записываем первый файл 3. Записываем длину второго файла 4. Записываем второй файл Чтение 1. Считываем длину первого файла 2. Считываем в переменную количество байт равных длине первого файла 3. Считываем длину второго файла 2. Считываем в переменную количество байт равных длине второго файла Верно?? Если нет, опишите пожалуйста, что-то непонимаю. |
Автор: pushok 16.8.2009, 20:54 | ||||
Ок. С позицией понял. Теперь такой вопрос. Пытаюсь записать два файла в один, а потом извлечь их. Процедура записи:
Файл '1.dat' появляется но занимает только 1 Кб Процедура чтения (пробовал также как и записи, но пишит какую-то ошибку, сделал по-другому)
Два файла появляются, но занимают они по 0 Кб каждый и ничего не содержат. В чем моя ошибка? (при этом если я второй файл выключаю из работы, т.е. пытаюсь сохранить только один, та же фигня) |
Автор: AntonN 16.8.2009, 21:17 |
м/у файловыми потоками сделай fs.CopyFrom(f,fs.Size); но предварительно не забывай задавать размер dest'у и устанавливать позиции (fs.position:=0;) |
Автор: kami 16.8.2009, 21:37 | ||||
Для записи: вместо
Соответственно - для чтения тоже. Вот в этом Ваша ошибка. Не нужно считать ошибку "какой-то". Ошибка имеет вполне конкретный смысл, конкретное значение, а при запуске под отладчиком (т.е. в Delphi ) - даже конкретную строчку, на которой происходит. Вот это всё и нужно проанализировать, и если самому непонятна причина ошибки, то все данные по ней - вывести сюда. Лишние телодвижения. нужно проще:
|
Автор: pushok 16.8.2009, 23:23 |
Спасибо всем = ))) все работает, вроде все ясно. CopyFrom тоже указатель двигает, как и Read, верно? |
Автор: AntonN 17.8.2009, 00:28 |
лучше считать что не двигает и делать все самому ![]() |
Автор: kami 17.8.2009, 07:32 |
Лучше. так. не. считать. Добавлено через 2 минуты и 28 секунд Read и Write перемещают указатель потока. соответственно - это делают и все их производные - Read|WriteBuffer; CopyFrom и т.д. Добавлено через 5 минут и 53 секунды Маленькое примечание: если есть TFileStream, с доступом fsOpenRead и в него попытаться что-нибудь записать, то ничего записано не будет и указатель соответственно не передвинется. Недавно потратил 20 минут на поиск этого своего глюка - не хотел файл записываться и все, размер=0 ![]() |
Автор: AntonN 17.8.2009, 10:41 | ||
Почему. лучше. ? |
Автор: MetalFan 17.8.2009, 14:42 |
смотря что подразумевается под "делать все самому"... если имеется ввиду неиспользование CopyFrom, то здесь я тоже не согласен. ХОТЯ есть некоторые моменты, когда CopyFrom не подходит... |
Автор: kami 17.8.2009, 17:08 |
![]() CopyFrom передвинет сам указатель на нужное количество байт. В этом случае манипуляции с Seek (или оберткой над ним - Position) - потенциальный глюкодром, причем достаточно неявный. Можно пример "навскидку"? Просто я всегда, когда нужно перекинуть данные из одного TStream в другой, пользуюсь CopyFrom (а его второй параметр :=0 - это вообще песня ![]() |
Автор: AntonN 17.8.2009, 18:12 | ||||
Вот когда ты вручную указываешь позицию куда писать - ты можешь точно видеть в коде откуда он пишет. А когда надеешься на невидимый указатель который "вроде бы должен быть тут" - вот это уже потенциальный глюкодром ![]() MetalFan,
подразумевается "выполнять position:=" когда точно нужно быть увереным в какую позицию должен установиться указатель. Добавлено через 7 минут и 5 секунд дополню на всякий случай, что опыта на стримах съел прилично, старый кусочек его вывалился в первых постах (который за час обрастает нужными полями в хедере (название файла, атрибуты и тп), прикручивается zlib и если надо шифрование). Никакого глюкодрома за годА плотного щупанья TFileStream.position я не встречал, зато часто натыкался на свои же грабли когда указатель после Write был не там, где должен быть перед очередной операцией (в основном связано было с модификацией кода, когда подзабывалась структура файла). |
Автор: kami 17.8.2009, 20:35 | ||||||
В контексте данной задачи это (на мой взгляд) будет выглядеть примерно так: 1. установить указатель в 0. Loop: 2. считать длину файла (и при необходимости - имя, атрибуты и т.д.) 3. запомнить позицию указателя 4. считать файл из потока 5. установить указатель на "запомненный"+длина файла goto Loop (пока не достигнем конца потока). Если доводить до абсурда - то каждая четная операция(2,4) тоже должна обрамляться запоминанием предыдущего положения указателя и ручным передвиганием его дальше. Извините, но... "это не наш метод". Большинство из посетителей форума могут сказать то же самое.
... не будем начинать холивар, тем более что к теме он относится слабо ![]() Добавлено через 1 минуту и 36 секунд
А именно поэтому Read и Write методы TStream - это функции. Возвращающие реальное количество считанного/записанного. |
Автор: MetalFan 17.8.2009, 21:10 | ||||
ребят, ну не устраивайте тут считалки. Ctrl+Click еще никто не отменял. а код CopyFrom не так уж и сложен для понимания. и сразу отпадут все вопросы, при каких входных данных этот злобный CopyFrom какие выходные данные оставит) если кому что-то непонятно, могу здесь код CopyFrom прокомментировать. да на здоровье) единственной проблемой, с которой я столкнулся при использовании метода TStream.CopyFrom, и из-за которой от него пришлось отказаться, это была проблема, связанная с использованием ZLib.TCompressStream, ZLib.TDecompressStream... в частности при распаковке потока следующим кодом:
ибо TDecompressionStream не умеет делать Seek(0, soFromEnd)... т.е. мы не узнаем размер распакованных данных, не распаковав их, или не сохранив из предварительно в том же потоке(к примеру). тогда вместо CopyFrom пришлось использовать нечто такое:
ну вот как-то так... |
Автор: kami 17.8.2009, 21:27 |
Ага, точно, есть такое. Одна из причин, из-за которых и перешел на FastZLib. |
Автор: MetalFan 18.8.2009, 11:25 |
а какие еще были причины? хотя это наверное уже злостный оффтоп будет) |
Автор: Yanis 18.8.2009, 11:26 |
Он уже был ![]() |