Показать полную графическую версию : .: NSIS - все вопросы :. часть 2.
Задача: "просмотреть" в папке все файлы и записать из них только нужное в другой файл. (соответственно с каждой строкой необходимо произвести манипуляции по нахождению-извлечению нужного)
Var FileCat
Var Name
Var Content
!macro FRead Name Content
ClearErrors
FileOpen $R5 "$EXEDIR\data.txt" w
FileOpen $R4 "$Name" r
${Do}
FileRead $R4 $Content
${IfThen} ${Errors} ${|} ${ExitDo} ${|}
MessageBox MB_OK "$Content"
FileWrite $R5 "$Name - $Content$\r$\n"
${Loop}
FileClose $R4
FileClose $R5
!macroend
Section
ClearErrors
FindFirst $0 $FileCat "$EXEDIR\TEST\*.*"
loop:
StrCmp $FileCat "" done
StrCmp $FileCat "." next
StrCmp $FileCat ".." next
StrCpy $Name "$EXEDIR\TEST\$FileCat"
!insertmacro FRead "$Name" "$Content"
next:
FindNext $0 $FileCat
Goto loop
done:
FindClose $0
SectionEnd
Для чтения-записи использую макрос с циклом FileRead. "Проверочный" MessageBox "фиксирует" данные в переменной из каждой строки каждого файла, но записываются данные только из одного файла, либо после обработки строк, вообще нечто рэндомное... В чём здесь ошибка ?
MKN,
FileOpen $R5 "$EXEDIR\data.txt" w
Файл открывается на запись с уничтожением содержимого.
AlekseyPopovv
01-11-2023, 10:13
Как "пропустить" ошибку:
"Невозможно открыть файл для записи:"
Т.е. если файл занят, просто пропустить его копирование без MessageBox.
Всем хорошего дня.
Помогите, пожалуйста с удалением папок.
Нигде не нашел, как удалить папки с расширением, например папки с расширением .tmp
Этот вариант не работает:
SetOutPath "$TEMP\*.tmp"
SetOutPath "$TEMP"
RMDir /r "$TEMP\*.tmp"
AlekseyPopovv
01-11-2023, 12:11
inco1, Стандартная команда RMDir /r не удалит папки по расширению. Надо знать как папки называются.
AlekseyPopovv, Я правильно понял, что в NSIS есть только команда удаления по маске файлов, а удаление по маске папок даже не предусмотрено?
AlekseyPopovv
01-11-2023, 12:29
inco1, Да.
AlekseyPopovv, Странно как то всё это, если для этой цели даже батник есть в одну крохотную строчку:
for /d %%d in (*.tmp) do rd /s /q %%d
Не совать же батник в инсталятор для таких случаев. :o
Как "пропустить" ошибку:
"Невозможно открыть файл для записи:"
Т.е. если файл занят, просто пропустить его копирование без MessageBox. »
SetOverwrite try
inco1, Странно как то всё это, если для этой цели даже батник есть в одну крохотную строчку
...»
Внезапно, команда rd тоже не умеет работать с масками.
Разница лишь в том, что в у интерпретатора командной строки есть готовые команды для циклов, а в nsis - нет.
Задача : необходимо в txt файле заменить конкретную строку на другую. Т.е. ,например, строку №5 удалить и заменить на содержимое из переменной и т.д.
Пробовал функцию - https://nsis.sourceforge.io/Replace_line_that_starts_with_specified_string
Не работает... (там правда не конкретная строка заменяется, а вроде как строка имеющая определённое вхождение, что тоже интересно, но тоже не заработало...)
Как решить такую задачу ?
MKN, Та функция вполне рабочая, хотя и перемудрена немного. Но применяемый там метод записи ломает хард/софт-линки
Вот так можно построить обработку конструкциями в стиле LogicLib:
ShowInstDetails show
RequestExecutionLevel user
InstallColors /windows
!include FileFunc.nsh
!include LogicLib.nsh
!include Util.nsh
; String begins with
!macro _[== _a _b _t _f
!insertmacro _LOGICLIB_TEMP
StrLen $_LOGICLIB_TEMP `${_b}`
StrCpy $_LOGICLIB_TEMP `${_a}` $_LOGICLIB_TEMP
StrCmp `$_LOGICLIB_TEMP` `${_b}` `${_t}` `${_f}`
!macroend
; String ends with
!macro _]== _a _b _t _f
!insertmacro _LOGICLIB_TEMP
StrLen $_LOGICLIB_TEMP `${_b}`
StrCpy $_LOGICLIB_TEMP `${_a}` '' -$_LOGICLIB_TEMP
StrCmp `$_LOGICLIB_TEMP` `${_b}` `${_t}` `${_f}`
!macroend
; String includes
!macro _*== _a _b _t _f
!insertmacro _LOGICLIB_TEMP
System::Call 'shlwapi.dll::StrStrI(ts, ts)p.s' `${_a}` `${_b}`
Pop $_LOGICLIB_TEMP
StrCmp $_LOGICLIB_TEMP 0 `${_f}` `${_t}`
!macroend
!define PathSplitPN `!insertmacro PathSplitPN `
!macro PathSplitPN outParent outName Path
!verbose push
!verbose ${_FILEFUNC_VERBOSE}
Push `${Path}`
${CallArtificialFunction} PathSplitPN_
Pop ${outName}
Pop ${outParent}
!verbose pop
!macroend
!macro PathSplitPN_
!verbose push
!verbose ${_FILEFUNC_VERBOSE}
Exch $0
Push $1
Push $2
StrCpy $1 $0 1 -1
StrCmp $1 '\' 0 +3
StrCpy $0 $0 -1
Goto -3
StrLen $2 $0
IntOp $2 $2 - 1
StrCpy $1 $0 1 $2
StrCmp $1 '\' +2
StrCmp $1 '' 0 -3
StrCpy $1 $0 $2 ; path
IntOp $2 $2 + 1
StrCpy $0 $0 '' $2 ; name
Pop $2
Exch $1
Exch
Exch $0
!verbose pop
!macroend
!define FileGetTempCopy `!insertmacro FileGetTempCopy `
!macro FileGetTempCopy outDuplicateName FullFileName
!verbose push
!verbose ${_FILEFUNC_VERBOSE}
Push `${FullFileName}`
Exch $0 ; [in] FullFileName / [out] outDuplicateName
Push $1 ; file path
Push $2 ; name / handle
Push $3 ; outDuplicateName
${PathSplitPN} $1 $2 $0
System::Call 'kernel32::GetTempFileName(tr1, tr2, i0, t.r3)i.r2'
${If} $2 != 0
FileClose $2
SetDetailsPrint none
CopyFiles /silent $0 $3
SetDetailsPrint lastused
${IfNot} ${Errors}
StrCpy $0 $3
${Else}
StrCpy $0 ''
SetDetailsPrint none
Delete $3
SetDetailsPrint lastused
${EndIf}
${Else}
StrCpy $0 ''
${EndIf}
Pop $3
Pop $2
Pop $1
Exch $0
Pop ${outDuplicateName}
!verbose pop
!macroend
!define FileReadByLine `!insertmacro _FileReadByLine '' `
!define FileReadByLineUTF16LE `!insertmacro _FileReadByLine UTF16LE `
!macro _FileReadByLine ENCODING LineNumberVar LineVar ReadFile WriteFile
!verbose push
!verbose ${LOGICLIB_VERBOSITY}
!insertmacro _PushScope FileProcessByLine _FileProcessByLine.${__COUNTER__}
!insertmacro _PushScope FileProcessByLineLineVar ${LineVar}
!insertmacro _PushScope FileProcessByLineENCODING '${ENCODING}'
!insertmacro _PushScope FileProcessByLineReadFile '${ReadFile}'
!insertmacro _PushScope FileProcessByLineWriteFile '${WriteFile}'
!ifndef _FileProcessByLine_Initialize_Variables
!define _FileProcessByLine_Initialize_Variables
Var /GLOBAL _FileProcessByLine_Var_RD
Var /GLOBAL _FileProcessByLine_Var_RDHANDLE
Var /GLOBAL _FileProcessByLine_Var_WR
Var /GLOBAL _FileProcessByLine_Var_LINE
Var /GLOBAL _FileProcessByLine_Var_LINENUMBER
!else
!define ${_FileProcessByLine}__Save_Vars
Push $_FileProcessByLine_Var_RD
Push $_FileProcessByLine_Var_RDHANDLE
Push $_FileProcessByLine_Var_WR
Push $_FileProcessByLine_Var_LINE
Push $_FileProcessByLine_Var_LINENUMBER
!endif
GetFullPathName $_FileProcessByLine_Var_RD `${ReadFile}`
${IfNotThen} ${FileExists} $_FileProcessByLine_Var_RD ${|} Goto ${_FileProcessByLine}__errors ${|}
${If} `${_FileProcessByLineWriteFile}` == ``
${OrIf} `${_FileProcessByLineWriteFile}` == `${_FileProcessByLineReadFile}`
StrCpy $_FileProcessByLine_Var_WR $_FileProcessByLine_Var_RD
${FileGetTempCopy} $_FileProcessByLine_Var_RD $_FileProcessByLine_Var_WR
${IfThen} $_FileProcessByLine_Var_RD == '' ${|} Goto ${_FileProcessByLine}__errors ${|}
${Else}
StrCpy $_FileProcessByLine_Var_RD `${ReadFile}`
StrCpy $_FileProcessByLine_Var_WR `${WriteFile}`
${EndIf}
ClearErrors
FileOpen $_FileProcessByLine_Var_RDHANDLE $_FileProcessByLine_Var_RD r
${If} ${Errors}
Goto ${_FileProcessByLine}__errors
${EndIf}
FileOpen $_FileProcessByLine_Var_WR $_FileProcessByLine_Var_WR w
${If} ${Errors}
FileClose $_FileProcessByLine_Var_RDHANDLE
Goto ${_FileProcessByLine}__errors
${EndIf}
StrCpy $_FileProcessByLine_Var_LINENUMBER 0
${Do}
FileRead${ENCODING} $_FileProcessByLine_Var_RDHANDLE $_FileProcessByLine_Var_LINE
${IfThen} ${Errors} ${|} ${ExitDo} ${|}
!define ${_FileProcessByLine}__LineNumberVar=${LineNumberVar}
!ifdef ${_FileProcessByLine}__LineNumberVar= | ${_FileProcessByLine}__LineNumberVar=-
!else
IntOp $_FileProcessByLine_Var_LINENUMBER $_FileProcessByLine_Var_LINENUMBER + 1
StrCpy ${LineNumberVar} $_FileProcessByLine_Var_LINENUMBER
!endif
!undef ${_FileProcessByLine}__LineNumberVar=${LineNumberVar}
StrCpy ${LineVar} $_FileProcessByLine_Var_LINE
; ...............
!verbose pop
!macroend
!define FileWriteByLine `!insertmacro _FileWriteByLine "" `
!define FileWriteByLineUTF16LE `!insertmacro _FileWriteByLine UTF16LE `
!macro _FileWriteByLine ENCODING
!verbose push
!verbose ${LOGICLIB_VERBOSITY}
!ifndef _FileProcessByLine
!error "Cannot use FileProcessByLineEnd${ENCODING} without a preceding FileProcessByLine${ENCODING}"
!endif
; ...............
FileWrite${ENCODING} $_FileProcessByLine_Var_WR ${_FileProcessByLineLineVar}
${Loop}
FileClose $_FileProcessByLine_Var_RDHANDLE
FileClose $_FileProcessByLine_Var_WR
${_FileProcessByLine}__errors:
SetErrors
${If} `${_FileProcessByLineWriteFile}` == ``
${OrIf} `${_FileProcessByLineWriteFile}` == `${_FileProcessByLineReadFile}`
SetDetailsPrint none
Delete $_FileProcessByLine_Var_RD
SetDetailsPrint lastused
${EndIf}
!ifdef ${_FileProcessByLine}__Save_Vars
!undef ${_FileProcessByLine}__Save_Vars
Pop $_FileProcessByLine_Var_LINENUMBER
Pop $_FileProcessByLine_Var_LINE
Pop $_FileProcessByLine_Var_WR
Pop $_FileProcessByLine_Var_RDHANDLE
Pop $_FileProcessByLine_Var_RD
!endif
!insertmacro _PopScope FileProcessByLine
!insertmacro _PopScope FileProcessByLineLineVar
!insertmacro _PopScope FileProcessByLineENCODING
!insertmacro _PopScope FileProcessByLineReadFile
!insertmacro _PopScope FileProcessByLineWriteFile
!macroend
Section TEST
SetDetailsPrint none
CopyFiles /silent '${__FILE__}' '${__FILE__}-1.txt'
CopyFiles /silent '${__FILE__}' '${__FILE__}-2INPLACE.txt'
CopyFiles /silent '${__FILE__}' '${__FILE__}-3.txt'
SetDetailsPrint lastused
/* вместо иснструкции:
${FileReadByLine} LineNumber Line FileToRead FileToWrite
LineNumber - переменная с номером строки или '' или '-' (не использовать)
Line - переменная со строкой (включает символы конца строки)
FileToRead - файл для чтения
FileToWrite - файл для записи
Если FileToWrite=='' или FileToWrite==FileToRead, будет изменён фходной файл
Внутри цикла
${FileReadByLine}
....
${Continue} завершит работу с текущей строкой, пропустит запись и перейдёт к чтению следующей строки
${Break} прекратит обработку
....
${FileWriteByLine}
${FileReadByLine} / ${FileReadByLineUTF16LE} - читать как ANSI / UTF16-LE
${FileWriteByLine} / ${FileWriteByLineUTF16LE} - писать как ANSI / UTF16-LE
*/
; пронумерует строки:
${FileReadByLine} $0 $1 '${__FILE__}-1.txt' '${__FILE__}-1NUMBERS.txt'
IntFmt $0 '%4d' $0
StrCpy $1 '[$0] $1'
${FileWriteByLineUTF16LE} ; сохранить в кодировке UTF16LE
; оставит и пронумерует только нечётные строки:
${FileReadByLine} $0 $1 '${__FILE__}-1.txt' '${__FILE__}-1ODDS.txt'
IntOp $2 $0 % 2
${IfThen} $2 == 0 ${|} ${Continue} ${|}
IntFmt $0 '%4d' $0
StrCpy $1 '[$0] $1'
${FileWriteByLine}
; удалит пустые строки, измениы ыходной файл:
${FileReadByLine} - $1 '${__FILE__}-2INPLACE.txt' ''
${IfThen} $1 == '$\r$\n' ${|} ${Continue} ${|}
; обработка прекратится на следующей строке:
${IfThen} $1 *== '; break on this line' ${|} ${Break} ${|}
${FileWriteByLine}
; вложенный цикл
${FileReadByLine} - $1 '${__FILE__}-1.txt' ''
${If} $1 [== 'Section '
${FileReadByLine} $0 $1 '${__FILE__}-3.txt' '${__FILE__}-3BLOCKS.txt'
${If} $1 [== '!macro '
${OrIf} $1 [== 'Function '
${OrIf} $1 [== 'Section '
IntFmt $0 '%4d' $0
StrCpy $1 '[$0] $1'
${Else}
${Continue}
${EndIf}
${FileWriteByLine}
${Break} ; завершить обработку
${EndIf}
${FileWriteByLine}
SectionEnd
iglezz, спасибо !, но очень мудрёно... Наивный практический вопрос - как выглядит то запрос на замену ? Скажем, входной файл In.txt , строка для замены №7, заменить на содержимое из $data.
ps Можно ли оформить функцию как .nsh ? (чтобы не очень пугала... :) )
Скажем, входной файл In.txt , строка для замены №7, заменить на содержимое из $data. »
Просто заменить седьмую строку на $data:
${FileReadByLine} $0 $1 'In.txt' ''
${IfThen} $0 == 7 ${|} StrCpy $1 $data ${|}
${FileWriteByLine}
Можно ли оформить функцию как .nsh ? »
Не можно, а нужно.
В примере оно из разных nsh подёргано.
iglezz,
Почему то после замены строки, следующая строка, имеющаяся в файле "прилепляется" к концу заменённой, т.е. после строки замены отсутствует перенос строки... Можно конечно после Line добавить $\r$\n, а может лучше в код функции добавить перенос, куда следует добавить ?
И можно ли в ${FileReadByLine} $0 $1 использовать свои переменные(вместо $0 $1) ?
Почему то после замены строки, следующая строка, имеющаяся в файле "прилепляется" к концу заменённой, т.е. после строки замены отсутствует перенос строки... Можно конечно после Line добавить $\r$\n, а может лучше в код функции добавить перенос, куда следует добавить ? »
Как и в инструкциях NSIS FileRead/FileReadUTF16LE строка (в пределах NSIS_MAX_STRLEN) считывается с символами завершения строки. Добавлять их обработку в макрос большого смысла нет, т.к. это замедлит и без того небыстрый код, а нужно не всегда.
Можно просто добавлять $\r$\n к переменной Line, если нет желания использовать EOL-символы для конкретной обрабатываемой строки.
И можно ли в ${FileReadByLine} $0 $1 использовать свои переменные(вместо $0 $1) ? »
Можно любые.
Тут, кстати, надо учитывать, что на строках длиннее NSIS_MAX_STRLEN работа может быть некоректной.
Для таких случаев нужна отдельная версия этой конструкции, в которой побочно и EOL-символы получатся в отдельной переменной.
AlekseyPopovv
01-12-2023, 07:51
В файле длинная строка, в ней нужно найти такие данные:
"download":{"default_directory":"C:\Пользователи\Downloads"}
Путь разный у всех.
Надо заменить на:
"download":{"default_directory":"$EXEDIR\${DEFDIR}\Downloads"}
Как это сделать по проще, если можно?
Подскажите пожалуйста - как приспособить RegistryFunc.nsh (из Справочника) для работы с UNICODE версиями NSIS ?
К сожалению сказано, что "библиотека полностью совместима только ANSI версией компилятора NSIS"...
MKN,
Посмотрев код по диагонали, могу сказать, что потребуется вдумчиво прогнать всё через дебаггер в голове на предмет выявления мест, где идёт работа на уровне байт, а не символов.
Параллельно можно и оптимизировать немного на производительность.
потребуется вдумчиво прогнать всё через дебаггер в голове на предмет выявления мест, где идёт работа на уровне байт, а не символов. Параллельно можно и оптимизировать немного на производительность. »
Вся надежда на тебя... :)
MKN, Большого смысла адаптировать RegistryFunc.nsh не вижу, проще новый написать с нуля.
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.
Available in ZeroNet 1osznRoVratMCN3bFoFpR2pSV5c9z6sTC