VB 6 Запись в указанную строку файла

Кирилл

Команда форума
Администратор
Ассоциация VN
Сообщения
14,069
Реакции
5,784
Привет.

Где то истина рядом, но у меня некоторый затык.
Как ни крути - какие то строки глотаются, а пишется только одна.
Функции для записи в указанную строку не нашел, поэтому следовал следующей логике:
1) Читаю файл построчно, каждую строку помещаю в переменную
2) Меняю одну из переменных на нужное мне значение
3) Затем в этот же файл записываю эти переменные по очереди.

Получается если какая то строка изменилась - значит перезапишется только эта строка, а остальные останутся без изменений.

VB.NET / VBA:
Private Sub Command1_Click()
Dim strSearch(5) As String, tmp(5) As String  'На данный момент в файле 5 строк, соответственно создаю массив из 5 переменных
MyFile = FreeFile
      k = 0 ' Заранее неизвестно количество строк, считаю через такую конструкцию, счет ведется с нуля  в переменную К
      Open "C:\Logg\1.txt" For Input As #MyFile
             Input #MyFile, tmp (5)
      Do Until EOF(MyFile)
            k = k + 1 ' Прибавляем по 1 строке после каждого прохода цикла до конца файла
            Input #MyFile, tmp(5)
      Loop
Close #MyFile

   
   
        Open "C:\Logg\1.txt" For Input As MyFile
            For i = 0 To k
            strSearch(i) = i ' Вообще количество переменных в массиве должно равняться количеству строк, по факту так и есть
                                    ' Каждый проход цикла задает элементу массива соответствующей строки
                  Line Input #MyFile, tmp(5)
                  strSearch(I) = tmp(i) ' При проходе цикла должна соотвествующему номеру строки назначиться ее значение такому же номеру элементу массива
            Next i
       
      Close #MyFile



Open "C:\Logg\1.txt" For Output As #MyFile ' Открываем файл
' Пишем обратно строки в порядке от 0 до конца
' И если нужно изменить какую то строку - просто меняем значение переменной
Print #MyFile, strSearch(0)
Print #MyFile, strSearch(1)
Print #MyFile, strSearch(2)
Close #MyFile ' Закрываем файл


End Sub

Может видно где я ошибся?
Можно ли вообще вести запись в нужную строки/строки по желанию напрямую?
 
Последнее редактирование:
Может вместо массивов использовать коллекции, а при чтении использовать построчное чтение?
По типу такого:
Код:
Do While MyFile.AtEndOfStream <> True
    TextLine = MyFile.ReadLine
    myCol.Add TextLine
Loop

А уже после "извращаться" с коллекцией как того захочется?
 
Можно ли вообще вести запись в нужную строки/строки по желанию напрямую?
Только если:
- у тебя структурированный файл (например, где-то хранишь инфу, какая строка начинается с какого № байта).
- или файл с фиксированной длинной записи (например, все строки имеют одинаковую длинну, тогда можно вычислить № байта начала любой строки).

Иначе, придётся читать весь файл целиком или по частям (если он слишком большой для размещения в памяти, или если его не целесообразно читать целиком).
Аналогично с записью, если тебе нужно заменить строку, и налагаемая строка имеет одинаковый размер с исходной, тогда да, ты можешь не читать весь файл и не перезаписываеть его полностью, а перезаписать только нужные байты.
Если налагаемая строка больше, то тебе в любом случае придётся перезаписывать байты, начиная с заменяемой строки и до конца файла (ну или весь файл полностью, если тебе так проще).
То же самое со случаем, когда налагаемая строка короче.

Если у тебя маленький файл, и хочется по-проще, то читаешь файл целиком, и командой Split помещаешь его в массив по разделителю CrLf (или просто Lf, если файл создан в ОС Linux). Я для надёжности обычно сначала удаляю из файла все знаки Cr, а затем разбиваю по разделителю Lf.
Затем ищешь в массиве и заменяешь нужную строку.
Перезаписываешь обратно весь файл целиком. Команда Join может выполнить слияние массива.
P.S. Коллекции работают на много медленнее. Хотя на маленьком файле ты этого не заметишь.
PPS. Если без Split / Join, учись пользоваться динамическими массивами. Redim и Redim preserve.

VB.NET / VBA:
Option Explicit

Private Sub Form_Load()
    On Error GoTo ErrorHandler

    Dim ff          As Integer
    Dim lSize       As Long
    Dim sContents   As String
    Dim sFile       As String
    Dim sSearch     As String
    Dim sReplace    As String
    Dim aTmp()      As String
    Dim i           As Long
    
    'исходный файл
    sFile = App.Path & "\Test.txt"
    
    sSearch = "искомая строка"
    sReplace = "замена"
    
    If Dir$(sFile) = "" Then MsgBox "Файл: " & sFile & " не существует!": Exit Sub
    
    'читаем файл целиком
    ff = FreeFile()
    Open sFile For Binary Access Read As #ff
        lSize = LOF(ff)
        'проверяем что файл не пустой
        If lSize > 0 Then
            'выделяем буфер нужной длинны
            sContents = String(lSize, 0)
            Get #ff, , sContents
        End If
    Close #ff
    
    'разбиваем строку по разделителю 0x0D 0x0A
    'предварительно удаляем все знаки 0x0D
    aTmp = Split(Replace(sContents, vbCr, ""), vbLf)
    
    'ищем нужную строку и заменяем
    For i = 0 To UBound(aTmp)
        'поиск без учёта регистра
        If StrComp(aTmp(i), sSearch, vbTextCompare) = 0 Then
            aTmp(i) = sReplace
            Exit For
        End If
    Next
    
    'записываем файл обратно, объединив все элементы массива с добавлением знаков 0x0D 0x0A (перенос строки) между ними
    sContents = Join(aTmp, vbCrLf)
    
    'открываем файл для записи
    ff = FreeFile()
    Open sFile For Binary Access Write As #ff
        Put #ff, , sContents
    Close #ff
    
    Exit Sub
ErrorHandler:
    MsgBox "Произошла непредвиденная ошибка: # " & Err.Number & ": " & Err.Description & ". LastDllErr = " & Err.LastDllError
End Sub

Ну и ещё учитывай, что в таких вещах важна кодировка. Данный код будет работать с ANSI (1251).
 
А ТекстСтрим разве не позволяет читать с указанного места и писать в указанное место?

Попробуйте читать построчно и записывать построчно во второй файл

MyFile1 = FreeFile
Open "C:\Logg\1.txt" For Input As #MyFile1
MyFile2 = FreeFile
Open "C:\Logg\2.txt" For Output As #MyFile2
Do Until EOF(MyFile1)
Line Input #MyFile1, X1
'X1 -> X2
Print #MyFile2, X2
Loop
Close
 
Последнее редактирование модератором:
Спасибо!
Разбираю все варианты уже из спортивного интереса.
И мой первоначальный вариант, кстати, работает если вместо
strSearch(I) = tmp(i)
Указывать явно:
If strSearch(i) = 0 then .....

Ну и далее по тексту.
 
Последнее редактирование:
Спасибо!
Разбираю все варианты уже из спортивного интереса.
И мой первоначальный вариант, кстати, работает если вместо
strSearch(I) = tmp(i)
Указывать явно:
If strSearch(i) = 0 then .....

Ну и далее по тексту.
,Кстати, если файл меньше 64 кБ, то его можно прочитать в текстовое поле или переменную целиком:

MyFile = FreeFile
Open "C:\Logg\1.txt" For Input As MyFile
Text1.Text = Input(LOF(MyFile), #MyFile) 'или в переменную Peremennaja = Input(LOF(MyFile), #MyFile)
Close MyFile

Потом работать в любом месте этого текста. Но помнить, что если в файл писалось посредством Print, то переход на новую строку = 2 символа (vbCr + vbLf (конец строки и конец абзаца))

Результат можно сохранить тоже целиком:

MyFile = FreeFile
Open "C:\Logg\1.txt" For Output As FNo1
Print #MyFile, Text1.Text 'или переменную Print #MyFile, Peremennaja
Close MyFile
 
Если в файле больше 64 кБ, то при таком чтении:
Text1.Text = Input(LOF(MyFile), #MyFile)
в текстовое поле будет прочитано только первые 64 кБ (это из личного опыта, возможно, что для не_XP или для не_VB6 будет по другому)
 
Последнее редактирование:
Назад
Сверху Снизу