I have an AutoIt script that works, mostly. Reads a file, writes out what I want, but it does not preserve the original newline character. If I read a UNIX format file (LF only), it will write out a Windows format file (CR and LF).
Short of switching to something more robust, like Python, how do I solve this in AutoIt?
Opt("MustDeclareVars", 1) ;0 = no, 1 = require pre-declare
#include <File.au3>
#include <Array.au3>
Local $gInPath = $CmdLine[1]
Local $NumberOfLines = $CmdLine[2]
Local $gInDrive, $gInDir, $gInFName, $gInExt, $gOutPath
Local $gMsgBoxTitle = "Error in " & #ScriptName
Local $InLine
Local $LineCount
Local $oFileIn
Local $oFileOut
Local $FileStringAppend
If FileExists($gInPath) Then
Else
MsgBox(4096, $gMsgBoxTitle, "This file does not exist" & #CRLF & $gInPath)
Exit
EndIf
_PathSplit($gInPath, $gInDrive, $gInDir, $gInFName, $gInExt)
If $NumberOfLines >= 1000000 Then
$FileStringAppend = $NumberOfLines / 1000000 & "M"
ElseIf $NumberOfLines >= 1000 Then
$FileStringAppend = $NumberOfLines / 1000 & "K"
Else
$FileStringAppend = $NumberOfLines
EndIf
$gOutPath = _PathMake($gInDrive, $gInDir, $gInFName & "_" & $FileStringAppend, $gInExt)
If FileExists($gOutPath) Then
MsgBox(4096, $gMsgBoxTitle, "File already exists" & #CRLF & $gOutPath)
Exit
EndIf
$oFileIn = FileOpen($gInPath, 0)
$oFileOut = FileOpen($gOutPath, 1)
; Check if file opened for reading OK
If $oFileIn = -1 Then
MsgBox(4096, $gMsgBoxTitle, "Unable to open file for read" & #CRLF & $gInPath)
Exit
EndIf
; Check if file opened for writing OK
If $oFileOut = -1 Then
MsgBox(4096, $gMsgBoxTitle, "Unable to open file for write." & #CRLF & $gOutPath)
Exit
EndIf
; Read in lines of text until the EOF is reached
$LineCount = 0
While 1
$InLine = FileReadLine($oFileIn)
$LineCount += 1
If #error = -1 Then ExitLoop
If $LineCount > $NumberOfLines Then ExitLoop
FileWriteLine($oFileOut, $InLine & #CRLF)
WEnd
FileClose($oFileIn)
FileClose($oFileOut)
Looking at the function documentation at this link - https://www.autoitscript.com/autoit3/docs/functions/FileWriteLine.htm . It appears you can leave off the & #CRLF in your FileWriteLine command.
AutoIt should use the same line terminator that is read in, or
"If the line does NOT end in #CR or #LF then a DOS linefeed (#CRLF)
will be automatically added."
Here's the solution I came up. It works, but I'm not sure it's the cleanest.
Opt("MustDeclareVars", 1) ;0 = no, 1 = require pre-declare
#include <File.au3>
#include <Array.au3>
Local $gInPath = $CmdLine[1]
Local $NumberOfLines = $CmdLine[2]
Local $gInDrive, $gInDir, $gInFName, $gInExt, $gOutPath
Local $gMsgBoxTitle = "Error in " & #ScriptName
Local $InLine
Local $LineCount
Local $oFileIn
Local $oFileOut
Local $FileStringAppend
Local Const $CHAR_READ_BLOCK = 100
Local $CharsRead = 0
Local $CrFound = 0
Local $LfFound = 0
Local $Newline
Local $InBlock
If FileExists($gInPath) Then
Else
MsgBox(4096, $gMsgBoxTitle, "This file does not exist" & #CRLF & $gInPath)
Exit
EndIf
_PathSplit($gInPath, $gInDrive, $gInDir, $gInFName, $gInExt)
If $NumberOfLines >= 1000000 Then
$FileStringAppend = $NumberOfLines / 1000000 & "M"
ElseIf $NumberOfLines >= 1000 Then
$FileStringAppend = $NumberOfLines / 1000 & "K"
Else
$FileStringAppend = $NumberOfLines
EndIf
$gOutPath = _PathMake($gInDrive, $gInDir, $gInFName & "_" & $FileStringAppend, $gInExt)
If FileExists($gOutPath) Then
MsgBox(4096, $gMsgBoxTitle, "File already exists" & #CRLF & $gOutPath)
Exit
EndIf
$oFileIn = FileOpen($gInPath, 0)
$oFileOut = FileOpen($gOutPath, 1)
; Check if file opened for reading OK
If $oFileIn = -1 Then
MsgBox(4096, $gMsgBoxTitle, "Unable to open file for read" & #CRLF & $gInPath)
Exit
EndIf
; Check if file opened for writing OK
If $oFileOut = -1 Then
MsgBox(4096, $gMsgBoxTitle, "Unable to open file for write." & #CRLF & $gOutPath)
Exit
EndIf
While $CrFound = 0 And $LfFound = 0
$CharsRead += $CHAR_READ_BLOCK
$InBlock = FileRead($oFileIn, $CharsRead)
If StringRight($InBlock, 1) = #CR Then
$InBlock = $InBlock & FileRead($oFileIn, $CharsRead)
EndIf
$CrFound = StringInStr($InBlock, #CR)
$LfFound = StringInStr($InBlock, #LF)
If $CrFound > 0 And $LfFound > 0 Then
$Newline = #CRLF
ElseIf $CrFound > 0 Then
$Newline = #CR
Else
$Newline = #LF
EndIf
WEnd
; Read first line of text
$InLine = FileReadLine($oFileIn, 1)
$LineCount = 1
FileWriteLine($oFileOut, $InLine & $Newline)
; Read in lines of text until the EOF is reached
While 1
$InLine = FileReadLine($oFileIn)
$LineCount += 1
If #error = -1 Then ExitLoop
If $LineCount > $NumberOfLines Then ExitLoop
FileWriteLine($oFileOut, $InLine & $Newline)
WEnd
FileClose($oFileIn)
FileClose($oFileOut)
Related
Instead of the MsgBox i want the script to read a .txt file and write to the end of each line the result of a variable, in my case is $FileSize
Here is the code for autoit script
#include <MsgBoxConstants.au3>
#include <File.au3>
Test()
Func Test()
For $i = 1 to _FileCountLines(#TempDir & "\myfiles.txt")
$mread = FileReadLine(#TempDir & "\myfiles.txt", $i)
Local $FileSize = FileGetSize($mread)
MsgBox($MB_SYSTEMMODAL, "", ByteSuffix($FileSize)) ;this is just a test
Next
EndFunc ;==>Example
Func ByteSuffix($Bytes)
Local $Index = 0, $aArray = [' bytes', ' KB', ' MB', ' GB', ' TB', ' PB', ' EB', ' ZB', ' YB']
While $Bytes > 1023
$Index += 1
$Bytes /= 1024
WEnd
Return Round($Bytes) & $aArray[$Index]
EndFunc
Here is the content of .txt file
C:\Users\G-PC\Documents\setup.exe
C:\Users\G-PC\Documents\config.ini
C:\Users\G-PC\Documents\image001.jpg
C:\Users\G-PC\Documents\image002.jpg
C:\Users\G-PC\Documents\image003.jpg
I want the following result
C:\Users\G-PC\Documents\setup.exe [SIZE FOR THIS]
C:\Users\G-PC\Documents\config.ini [SIZE FOR THIS]
C:\Users\G-PC\Documents\image001.jpg [SIZE FOR THIS]
C:\Users\G-PC\Documents\image002.jpg [SIZE FOR THIS]
C:\Users\G-PC\Documents\image003.jpg [SIZE FOR THIS]
There is a size limit for both string variables and arrays, so you have to process one line at a time when working with big files. This uses a temporary file for output instead of keeping all the information in memory. You can rename (overwriting the original file) the temporary file to the original file name at the end.
Func Test()
Local $InFile = FileOpen(#TempDir & "\myfiles.txt", $FO_READ)
Local $OutFile = FileOpen(#TempDir & "\myfiles.tmp", $FO_OVERWRITE)
While True
$File = FileReadLine($InFile)
If #error = -1 Then Return ; no more lines to process
FileWrite($OutFile, $File & " [" & ByteSuffix(FileGetSize($File)) & "]" & #CRLF)
WEnd
EndFunc ;==>Test
$sResult = Test()
ConsoleWrite('SIZE LIST' & #CRLF & $sResult)
Func Test()
Local $FileSize, $sReturn = ''
For $i = 1 to _FileCountLines(#TempDir & "\myfiles.txt")
$mread = FileReadLine(#TempDir & "\myfiles.txt", $i)
$FileSize = FileGetSize($mread)
; MsgBox($MB_SYSTEMMODAL, "", ByteSuffix($FileSize)) ;this is just a test
$sReturn &= $mread & " [" & ByteSuffix($FileSize) & "]" & #CRLF
Next
Return $sReturn
EndFunc ;==>Test
But a better way instead of reading the text file line by line is the using of _FileReadToArray. Than you can iterate through the array with text lines.
Using line number parameter for FileReadLine in a loop resets
the file pointer to the start and scans up to the line number which slows
down the loop as line count increases. Omit that parameter.
Use a file handle so you do not keep on opening and closing
the file with each line read in the loop.
#include <MsgBoxConstants.au3>
#include <File.au3>
$sResult = Test()
MsgBox(0, #ScriptName, $sResult)
Func Test()
Local $iFileSize, $hFile, $sFilePath, $sResult
; Open a file handle to read.
$hFile = FileOpen(#TempDir & "\myfiles.txt")
If $hFile = -1 Then
MsgBox(0x30, #ScriptName, 'Unable to open file to read.')
Exit 1
EndIf
While 1
; Read and let AutoIt handle line count.
$sFilePath = FileReadLine($hFile)
If #error Then ExitLoop
$iFileSize = FileGetSize($sFilePath)
If #error Then ContinueLoop
$sResult &= StringFormat('%s %s\r\n', $sFilePath, ByteSuffix($iFileSize))
WEnd
FileClose($hFile)
Return $sResult
EndFunc
Func ByteSuffix($Bytes)
Local $Index = 0
Local $aArray = [' bytes', ' KB', ' MB', ' GB', ' TB', ' PB', ' EB', ' ZB', ' YB']
While $Bytes > 1023
$Index += 1
$Bytes /= 1024
WEnd
Return Round($Bytes) & $aArray[$Index]
EndFunc
I need to know how to post file name variable to desired one instead of "upload.zip"
i know how to automate file name using php only but required autoit to post variable of file name using tcpsend method
Thanks
PHP code:
<?php
print_r($_POST);
print_r($_FILES);
copy($_FILES["upload"]["tmp_name"], "upload.zip");
?>
Autoit code:
ConsoleWrite(_PHPupload('192.168.1.2', _OSmacros(), 89, '/upload/index.php', 'application/zip') & #CRLF)
Func _PHPupload($pIP, $pMacros, $pPort, $phpPath, $pContent)
If FileExists($pFile) = 0 Then Return SetError(1, 1, '')
$pTcpc = TCPConnect($pIP, $pPort)
If #error Then Return SetError(1, 2, '')
Local $pBound = "-----" & Random(10000000, 99999999, 1)
Local $pData1 = "--" & $pBound & #CRLF
$pData1 &= 'Content-Disposition: form-data; name="upload"; filename="' & $pFile & '"' & #CRLF & 'Content-Type: ' & $pContent & #CRLF & #CRLF
Local $pData2 = #CRLF & "--" & $pBound & #CRLF & 'Content-Disposition: form-data ;name="test"' & #CRLF & #CRLF & "variable" & #CRLF
$pData2 &= "--" & $pBound & "--" & #CRLF & #CRLF
Local $pHeader = 'POST ' & $phpPath & ' HTTP/1.1' & #CRLF
$pHeader &= 'Host: ' & $pIP & #CRLF
$pHeader &= 'User-Agent: ' & $pMacros & #CRLF
$pHeader &= 'Content-Type: multipart/form-data; boundary=' & $pBound & #CRLF
$pHeader &= 'Content-Length: ' & (StringLen($pData1) + StringLen($pData2) + FileGetSize($pFile)) & #CRLF & #CRLF
Local $pFopen = FileOpen($pFile, $FO_READ)
If $pFopen = -1 Then Return SetError(1, 3, '')
Local $sFread = FileRead($pFopen)
TCPSend($pTcpc, $pHeader & $pData1 & $sFread & $pData2)
If #error Then Return SetError(1, 4, '')
Local $pBuffer = ""
While 1
$pBuffer &= TCPRecv($pTcpc, 1024)
If #error Then
Return SetError(1, 5, '')
Else
ExitLoop
EndIf
WEnd
MsgBox(64, "", $pBuffer)
EndFunc ;==>_PHPupload
$pFile is not declared, but even if it is, it wont work because its a
filepath and you are sending it as a filename at
filename="' & $pFile
This should work:
ConsoleWrite(_PHPupload('192.168.1.2', _OSmacros(), 89, '/upload/index.php', 'application/zip', "c:\somedir", "somefile.zip") & #CRLF)
Func _PHPupload($pIP, $pMacros, $pPort, $phpPath, $pContent, $pFilePath, $pFileName)
$pFile = $pFilePath & "\" & $pFileName
If FileExists($pFile) = 0 Then Return SetError(1, 1, '')
$pTcpc = TCPConnect($pIP, $pPort)
If #error Then Return SetError(1, 2, '')
Local $pBound = "-----" & Random(10000000, 99999999, 1)
Local $pData1 = "--" & $pBound & #CRLF
$pData1 &= 'Content-Disposition: form-data; name="upload"; filename="' & $pFileName & '"' & #CRLF & 'Content-Type: ' & $pContent & #CRLF & #CRLF
Local $pData2 = #CRLF & "--" & $pBound & #CRLF & 'Content-Disposition: form-data ;name="test"' & #CRLF & #CRLF & "variable" & #CRLF
$pData2 &= "--" & $pBound & "--" & #CRLF & #CRLF
Local $pHeader = 'POST ' & $phpPath & ' HTTP/1.1' & #CRLF
$pHeader &= 'Host: ' & $pIP & #CRLF
$pHeader &= 'User-Agent: ' & $pMacros & #CRLF
$pHeader &= 'Content-Type: multipart/form-data; boundary=' & $pBound & #CRLF
$pHeader &= 'Content-Length: ' & (StringLen($pData1) + StringLen($pData2) + FileGetSize($pFile)) & #CRLF & #CRLF
Local $pFopen = FileOpen($pFile, $FO_READ)
If $pFopen = -1 Then Return SetError(1, 3, '')
Local $sFread = FileRead($pFopen)
TCPSend($pTcpc, $pHeader & $pData1 & $sFread & $pData2)
If #error Then Return SetError(1, 4, '')
Local $pBuffer = ""
While 1
$pBuffer &= TCPRecv($pTcpc, 1024)
If #error Then
Return SetError(1, 5, '')
Else
ExitLoop
EndIf
WEnd
MsgBox(64, "", $pBuffer)
EndFunc ;==>_PHPupload
I'm trying to realize a little script in Autoit that retrieves all IPs used by Facebook servers (query "-i origin AS32934" to whois.radb.net, as developer page says), but I don't understand why WhoIs servers are not responding to my queries.
This is the script:
Local $host = "whois.radb.net", $query = "-i origin AS32934"
If Ping($host) Then
$ws = DllOpen("ws2_32.dll")
TCPStartup()
$ip = TCPNameToIP($host)
If #error Then _err("TCPNameToIP", #error)
Global $socket = TCPConnect($ip, 43)
If #error Then _err("TCPConnect", #error)
TCPSend($socket, $query)
If #error Then _err("TCPSend", #error, 1)
Local $text = "", $t = TimerInit(), $counter = 0
While 1
$recv = TCPRecv($socket, 2048)
If #error And #error <> -1 Then
$aRet = DllCall($ws, "int", "WSAGetLastError")
MsgBox(16,"ERROR", "Function: TCPRecv" & #CRLF & "Last data received: " & $recv & #CRLF & "Winsock error: " & $aRet[0] & #CRLF & "Loop executed " & $counter & " times")
ExitLoop
EndIf
$text &= $recv
$counter += 1
If TimerDiff($t) > 4999 Then ExitLoop
WEnd
If $text = "" Then
MsgBox(48, "RESULT", "EMPTY" & #CRLF & "Loop executed " & $counter & " times")
Else
MsgBox(0, "RESULT", $text)
EndIf
TCPCloseSocket($socket)
TCPShutdown()
Else
_err("Ping", #error, 0)
EndIf
Func _err($func, $err, $opt = 2)
MsgBox(16, "ERROR", "Function: " & $func & #CRLF & "Error: " & $err)
If $opt = 1 Then TCPCloseSocket($socket)
If $opt > 0 Then TCPShutdown()
Exit
EndFunc
The output is always "RESULT:EMPTY".
I've tried to query other WhoIs services with various queries (for example whois.verisign-grs.com with "=facebook.com") but I get no response.
It's not a problem about my network, because I've tried a Nirsoft WhoIs tool ad it works.
I've downloaded a sniffer and this is the output when I start my script:
==================================================
Protocol : TCP
Local Address : 192.168.1.101
Remote Address : 198.108.0.18
Local Port : 23509
Remote Port : 43
Remote Host : whois.radb.net
Service Name : nicname
Packets : 5 {5 ; 0}
Data Size : 17 Bytes {17 ; 0}
Total Size : 274 Bytes {217 ; 57}
Data Speed : 0.0 KB/Sec
Capture Time : 07/07/2014 15:18:37:313
Last Packet Time : 07/07/2014 15:18:45:837
Duration : 00:00:08.523
==================================================
Content:
-i origin AS32934
It seems the packet is sent but no packet is received.
I just found out the solution: adding a #crlf at the end of TCPSend() request
$query = "-i origin AS32934" & #crlf
So I am in need of replacing string text with autoit using stringreplace but I need to randomize the output.
An example of what I need is
Stringreplace($string, "and", {also|as well})
My ultimate goal is to randomly replace the text with the following options based on the word "and" with also or as well
I wrote this a long time ago.
It will convert this
My name is {John|Peter|Mark}! {Regards|Cheers|Get lost}!
to something like this
My name is John! Cheers!
It works with line breaks also.
Func SpintaxToTXT($TextWithSpintax)
Dim $MSGMSG
Dim $lines
$lines = StringSplit($TextWithSpintax, #LF)
For $z = 1 To $lines[0]
If $z > 1 Then $MSGMSG &= #LF
$d = StringSplit($lines[$z], "{}")
For $i = 1 To $d[0]
$MSGSplit = StringSplit($d[$i], "|")
If #error Then
$MSGMSG &= $MSGSplit[1]
ContinueLoop
EndIf
$MSGMSG &= $MSGSplit[Random(1, $MSGSplit[0], 1)]
Next
Next
Return $MSGMSG
EndFunc ;==>SpintaxToTXT
Try this:
Global $options_A = StringSplit('also,as well,bla,blubb,that,this', ',', 2)
For $i = 0 To 20
ConsoleWrite($options_A[Random(0, UBound($options_A) - 1, 1)] & #CRLF)
Next
Here's one I made earlier. Works exactly the same as StringReplace except instead of taking a replacement string, it takes a function that returns the replacement string. The using Xenobiologist's array method, you get the desired result.
Local $sTest = "The cat and the dog and the rat."
ConsoleWrite(_StringReplaceCallback($sTest, "and", _MyCallback) & #LF)
Func _MyCallback($s)
Local Static $aOptions = StringSplit("also|as well", "|")
Return $aOptions[Random(1, $aOptions[0], 1)]
EndFunc ;==>_MyCallback
Func _StringReplaceCallback($sString, $sFind, $funcReplace, $iOccurence = 0, $iCaseSense = 0)
Local $sRet = ""
Local $iDir = 1
Local $iPos = 1
If $iOccurence < 0 Then
$iDir = -1
$iPos = StringLen($sString)
EndIf
If $iOccurence = 0 Then $iOccurence = $iDir * StringLen($sString)
While 1
$i = StringInStr($sString, $sFind, $iCaseSense, $iDir, $iPos)
If $iDir > 0 Then
If Not $i Or Not $iOccurence Then
$sRet &= StringMid($sString, $iPos)
ExitLoop
EndIf
$sRet &= StringMid($sString, $iPos, $i - $iPos) & $funcReplace($sFind)
$iPos = $i + StringLen($sFind)
Else
If Not $i Or Not $iOccurence Then
$sRet = StringMid($sString, 1, $iPos) & $sRet
ExitLoop
EndIf
$sRet = $funcReplace($sFind) & StringMid($sString, $i + StringLen($sFind), $iPos - $i - StringLen($sFind) + 1) & $sRet
$iPos = $i - 1
EndIf
If $iOccurence <> 0 Then $iOccurence -= $iDir
WEnd
Return $sRet
EndFunc ;==>_StringReplaceCallback
It's probably worth noting that there is actually a simpler solution for this, provided the replacement strings don't ever include "and" (or else you'll have an infinite loop), that just replaces one instance at a time:
Local $sString = "The cat and the dog and the rat."
Local $aOptions = StringSplit("also|as well", "|")
Do
$sString = StringReplace($sString, "and", $aOptions[Random(1, $aOptions[0], 1)], 1)
Until Not #extended
ConsoleWrite($sString & #LF)
I have a text file contains nearly 20 lines wanted to search a string in file and print next 5th line in file using autoit, any one can help me to solve this
#include <File.au3>
#include <array.au3>
$file = #ScriptDir & "\file.txt"
$search = "str"
If FileExists($file) Then
$contents = FileRead($file)
If #error Then
MsgBox(0, 'File Error', $file & ' could not be read.')
Else
For $i = 1 To $count
If StringInStr($contents, $search) Then
MsgBox(0, 'Positive', $file & ' does contain the text "' & $search & '"')
Else
MsgBox(0, 'Negative', $file & ' does NOT contain the text "' & $search & '"')
EndIf
Next
EndIf
EndIf
This reads the text file until the search string is found and then writes the next 5 lines to STDOUT:
#include <File.au3>
#include <Array.au3>
Global $file = #ScriptDir & "\file.txt", $search = "str"
Global $iLine = 0, $sLine = ''
Global $hFile = FileOpen($file)
If $hFile = -1 Then
MsgBox(0,'ERROR','Unable to open file for reading.')
Exit 1
EndIf
; find the line that has the search string
While 1
$iLine += 1
$sLine = FileReadLine($hFile)
If #error = -1 Then ExitLoop
; $search found in the line, now write the next 5 lines to STDOUT
If StringInStr($sLine, $search)And Not $iValid Then
For $i = $iLine+1 To $iLine+5
ConsoleWrite($i & ':' & FileReadLine($hFile, $i) & #CRLF)
Next
ExitLoop
EndIf
WEnd
FileClose($hFile)
Edit
Due to Matt's argument here's a 2nd version of the loop that doesn't use the "line" parameter for FileReadLine.
#include <File.au3>
#include <Array.au3>
Global $file = #ScriptDir & "\file.txt", $search = "str"
Global $iLine = 0, $sLine = '', $iValid = 0
Global $hFile = FileOpen($file)
If $hFile = -1 Then
MsgBox(0,'ERROR','Unable to open file for reading.')
Exit 1
EndIf
; find the line that has the search string
While 1
$iLine += 1
$sLine = FileReadLine($hFile)
If #error = -1 Then ExitLoop
; test the line for the $search string until the flag $iValid is set
If StringInStr($sLine, $search) And Not $iValid Then
$iValid = 1
ContinueLoop
EndIf
If $iValid Then
$iValid += 1
ConsoleWrite($iLine & ':' & $sLine & #CRLF)
If $iValid > 5 Then ExitLoop
EndIf
WEnd
FileClose($hFile)
You won't note much difference between those two versions of the script, unless you are reading a file with 10k+ lines and the lines you are looking for are in the last quarter of that file but it surely is a good idea to prevent possible performance issues.