Консультация № 170346
10.07.2009, 22:57
0.00 руб.
0 11 1
Здравствуйте!
У меня задача: надо сначала "разрубить" один файл на два, а потом склеить их в один.
Я написал программу для деления файла на 2 части, однако если сложить кол-во байт в одной части и в другой части, то кол-во их получается заметно большим, чем в исходном файле. Исходный файл представляет собой картинку. Также написал программу для "склеивания" - и тут у меня получается "битый" файл, т.е. искажения цветов и сдвиг. Подскажите, пожалуйста, в чем проблема? Коды в приложении. Язык: VB6. Бьюсь уже не одну неделю, не могу понять, что не так.
ОЧЕНЬ надеюсь на помощь! Спасибо!

Приложение:
Никаких объектов на форме нет.
Код разделителя:
Private Sub Form_Load()
Dim F, F1, F2
F = FreeFile
Open App.Path & "\ioo.bmp" For Binary As #F
F1 = FreeFile
Open App.Path & "\p1.bmp" For Binary As #F1
F2 = FreeFile
Open App.Path & "\p2.bmp" For Binary As #F2
Dim Part1 As Long, Part2 As Long, Ob As Long, K As Long, Part2_N As Long, Kb As Long, Kb2 As Long
Ob = FileLen(App.Path & "\ioo.bmp")
Part1 = Int(Ob / 2)
Part2_N = Part1 + 1
Part2 = Part1 * 2
Dim S As String
S = String(256, vbNullChar)
For K = 1 To Part2 Step 256
If K <= Part1 Then Get #F, K, S: Put #F1, , S: Kb = K
If (K + Part2_N) <= Part2 Then Get #F, K + Part2_N, S: Put #F2, , S: Kb2 = K + Part2_N
If (K + 256) >= Part2 Then Exit For
Next
Dim Dm As Byte
Kb = Kb + 1
For K = Kb To Part1
Get #F, K, Dm
Put #F1, , Dm
Next
Kb2 = Kb2 + 1
For K = Kb2 To FileLen(App.Path & "\ioo.bmp")
Get #F, K, Dm
Put #F2, , Dm
Next
Reset
MsgBox "Âñ¸ ÎÊ!", vbInformation, "Status"
End
End Sub

Код собирателя:
Private Sub Form_Load()
Dim MyF, MyFF
Dim A() As Byte
ReDim A(5242879) As Byte
Dim L As Long, L1 As Long
If FileLen(App.Path & "\2.bmp") >= 5242880 Then
L = FileLen(App.Path & "\2.bmp")
L1 = Int(L / 5242880)
MyF = FreeFile
Open App.Path & "\1.bmp" For Binary As #MyF
MyFF = FreeFile
Open App.Path & "\2.bmp" For Binary As #MyFF
For k = 1 To L1
Get #MyFF, , A
Put #MyF, , A
Next
L1 = L - Loc(MyFF)
ReDim A(L1 - 1) As Byte
Get #MyFF, , A
Put #MyF, , A
Close #MyF
Close #MyFF
MsgBox "Ãîòîâî!!", vbInformation, "ÃîòîâÎ!"
End
Else
MyF = FreeFile
Open App.Path & "\1.bmp" For Binary As #MyF
MyFF = FreeFile
Open App.Path & "\2.bmp" For Binary As #MyFF
ReDim A(FileLen(App.Path & "\2.bmp") - 1) As Byte
Get #MyFF, , A
Put #MyF, FileLen(App.Path & "\1.bmp"), A
Close #MyF
Close #MyFF
MsgBox "Ãîòîâî!!", vbInformation, "ÃîòîâÎ!"
End
End If
End Sub

Обсуждение

Неизвестный
10.07.2009, 23:42
общий
А вот это пробовали - http://www.vbnet.ru/samples/download.aspx?id=292? Написано, что работает как разделитель файлов.
Неизвестный
11.07.2009, 00:39
общий
Нет, это не пробовал.ОГРОМНОЕ спасибо!
Неизвестный
11.07.2009, 01:13
общий
AkaProc:
А что за такой хитрый способ разделения? Разрезать пополам надо, или по какому-то сложному алгоритму? Из кода логика не очень понятна :)
Неизвестный
11.07.2009, 11:06
общий
Да, надо разрезать пополам любым способом, но чем быстрее будет работать программа, тем лучше. Мой код работает так: длину файла в байтах мы делим пополам, затем отсекаем дробную часть - это и будет размер одной части. Затем вычисляем пределы одного сегмента и второго. Потом организуем цикл, где каждая его часть будет писать свой сегмент исходного файла в свой файл. Поскольку я пишу в переменную длиной 256 байт, а размер части далеко не всегда кратен 256, то, чтобы дойти до своих пределов, необходимо создать дополнительный цикл, в котором мы организуем "дохождение" до конца пределов побайтно. После чего закрываем файлы. Вот и все.
Неизвестный
11.07.2009, 23:32
общий
это ответ
Здравствуйте, AkaProc.

Код не стал даже разбирать. Непонятны многие действия. По обфускации хорошая оценка бы была. По его мотивам написал работающую программу. На форме 2 кнопки - Разрезать и Склеить. Файл "ioo.bmp" должен быть в корне диска. Остальные файлы создаются там же.

Основа - процедура CopyPartOfFile. Она сначала копирует целыми блоками, а для остатка создает свой блок. BlockSize можно увеличить до пары десятков килобайт.

Приложение:
Option Explicit

Public Sub SplitFile(Source As String, T1 As String, T2 As String)
Dim F As Integer, F1 As Integer
Dim Size As Long, Half As Long
F = FreeFile
Open Source For Binary As #F
Size = FileLen(Source)
Half = Size \ 2

F1 = FreeFile
Open T1 For Binary As #F1
CopyPartOfFile F, F1, Half
Close F1

F1 = FreeFile
Open T2 For Binary As F1
CopyPartOfFile F, F1, Size - Half
Close F1
Close F
End Sub

Public Sub Combinefile(Target As String, S1 As String, S2 As String)
Dim F As Integer, F1 As Integer
Dim Size As Long
F = FreeFile
Open Target For Binary As #F

F1 = FreeFile
Open S1 For Binary As #F1
Size = FileLen(S1)
CopyPartOfFile F1, F, Size
Close F1

F1 = FreeFile
Open S2 For Binary As F1
Size = FileLen(S2)
CopyPartOfFile F1, F, Size
Close F1
Close F
End Sub

Public Sub CopyPartOfFile(Source As Integer, Target As Integer, Count As Long)
Const BlockSize = 256
Dim S As String
Dim N As Long, i As Long
S = String(BlockSize, vbNullChar)
N = Count \ BlockSize
'Copy whole Blocks
For i = 1 To N
Get Source, , S
Put Target, , S
Next i
'Copy the Rest
N = Count Mod BlockSize
If N <> 0 Then
S = String(N, vbNullChar)
Get Source, , S
Put Target, , S
End If
End Sub

Private Sub Command1_Click()
SplitFile "\ioo.bmp", "\p1.bmp", "\p2.bmp"
End Sub

Private Sub Command2_Click()
Combinefile "\ioo.bmp.new", "\p1.bmp", "\p2.bmp"
End Sub
5
Благодарю! Буду изучать. :)
Неизвестный
12.07.2009, 12:43
общий
Ура! Я нашел ошибку у себя: она состояла в том, что я пытался не создать новый файл, а "дописать" файл, где содержится первая часть. Но дело в том, что я никак не могу понять, почему у меня не получается все остальные части "слить" с первой, не переписывая первую часть в новый файл? Я слышал, что там добавляется какая-то служебная информация, не знаете, можно ли как-нибудь обойти это? А ядра наших программ полностью в рабочем состоянии.
Неизвестный
12.07.2009, 21:27
общий
AkaProc:
По поводу склеивателя:
1 Функция состоит из огромного if. Надо либо вынести "общий знаменатель" за его пределы, либо оформить части как отдельные процедуры. Но не в данном случае. Вторая часть его полность реализуется в первой. Она вообще не нужна. Зачем так усложнять?
2 Вы копируете второй файл ПОВЕРХ первого (в первой части). Сначала надо перенести текущую позицию за последний байт.
Open "\1.bmp" For Binary As #MyF
Seek MyF, FileLen("\1.bmp") + 1
3 ReDim A(5242879) As Byte - Издевательсто над мозгом. И при копировании в другую программу может привести к ошибке. Нижняя граница по умолчанию 1 ИЛИ 0.
4 Во второй части неправильно вычислена позиция. См 2

Главная ошибка - Вы много раз переписываете один и тот же код, да еще и каждый раз чуть по-другому. Соответственно, много ошибок, и в каждом участке кода они разные. Старайтесь не клонировать код, а искать похожее и вычленять это в функции и циклы. Такая программа не всегда короче, но ее сложность остается в более-менее приличных рамках. Если посидеть и избавиться от блока else, эта программа вполне может быть красивой.
Для сравнения файлов используются реинкарнации программы diff. Есть встроенные во многие файловые менеджеры. Сравните исходный файл со склеенным - сразу можно понять, где неправильные байты начинаются. Без магической служебной информации :)
Неизвестный
13.07.2009, 13:01
общий
Большое спасибо за совет! Теперь у меня получилось "сливать" первую часть со всеми остальными. Я проверял судя по размеру файла - все сливается правильно. Я делю файл на 4 части.ReDim A(5242879) As Byte - это 5 МБ буффер. Нижняя граница - 0. Насчет перерисывания кода - я с Вами полностью согласен - я тогда хотел хоть как-то добиться работоспособности, а потому поленился писать в виде процедур и функций, а вторую часть кода, которая предназначена для файлов менее 5 МБ, скопировал с первой части и чуть-чуть модифицировал. Но, ничего, теперь можно будет поработать над программой и оформить ее как полагается.Если бы Вы мне не подсказали оператор "Seek", то я долго бы еще возился, а так все получилось сходу. :)
Неизвестный
13.07.2009, 16:52
общий
Проверять по размеру чревато. Тут байтик затер, там нолик лишний - вот размер и совпал. Специфика ошибок с индексами.
Границы массива лучше задавать явно и с единицы, раз язык позволяет. Так проще. На скорости это не отразится. Если в начале программы поставить Option Base 1, массивы будут начинаться с 1. И код станет работать неверно. А эту опцию многие используют.
Бейсик вообще провоцирует плохое написание кода. Это болезнь языка. Я приучился писать код "с конца". Например, мою программу я начал с процедуры CopyPartOfFile, а затем уже писал функции, которые ее используют. Так на каждой стадии есть конкретная цель и инструменты. Надо к ней стремиться. Если начинать с открытия файлов - цель размыта, код тоже выходит "лишь бы тут сработало". Если не начинать "по-быстрому", готовая программа часто гораздо быстрее получается. А сначала у меня тоже не каждая программа доводилась до рабочего состояния: запутывался в дебрях. :)
Неизвестный
14.07.2009, 12:25
общий
Благодарю за совет! На самом деле можно просто задавать массив так, пример: Dim A(1 To 300) as Byte - в этом случае номера будут от 1 до 300. Начет того, что проверять по размеру чревато... даже не знаю... по-моему, если не ставить тут эту опцию, то заминка будет только в месте, где мы задаем массив, т.к. по умочанию элементы будут с нуля, а потом все как обычно, главное, на этом моменте не ошибиться. А почему Вы говорите, что Бейсик провоцирует плохое написание кода, что Вы имеете ввиду ? По-моему Бейсик - один из лучших языков: у него много возможностей, он быстро учится, он может даже сам исправлять некоторые ошибки. Мне он очень нравится. Тем более, его возможности расширяются с использованием API.
Неизвестный
14.07.2009, 20:00
общий
Про размер: я имел в виду файл. Если размер совпадает, это еще не значит, что содержимое правильное.
На Бейсике можно писать хорошо структурированные программы, но не хочется. Так уж сложилось. Он воспринимается как промежуточный между строгими языками и "языками сценариев". И пишут на нем все как бог на душу положит. Это и недостаток, и достоинство. Я на нем до сих иногда алгоритмы прорабатываю. Написать на нем программку "на выброс" легче, чем на том же C# - устаешь меньше. А после отработки можно ее на рабочем языке переписать. И шестая студия мусорных файлов не оставляет в таких случаях. Мне это в ней больше всего нравится :)
Форма ответа