Passing file arguments to script in Lua - file-io

I need to read a input file which name I do not know.
I know that in C we can do this:
FILE *Ifile;
File *Ofile;
int main(int argc, char *argv[]){
// Input and Output files
Ifile = fopen(argv[1],"r");
Ofile = fopen(argv[2],"w");
(More code)
}
and then call "./cprogram <any file name>.txt <any file name>.txt"
Can I do something like this with .Lua scripts?

Yes, you can. From the documentation:
Before starting to run the script, lua collects all arguments in the command line in a global table called arg. The script name is stored at index 0, the first argument after the script name goes to index 1, and so on.
For example, you could do the following:
if #arg < 2 then
print ("usage: lua " .. arg[0] .. " <ifile> <ofile>")
return
end
local ifile = io.open(arg[1], "r")
local ofile = io.open(arg[2], "w")
if not ifile or not ofile then
print ("Error: could not open files")
return
end

Related

Opening multiple files from folder in DigitalMicrograph scripting

I am trying to write a DigitalMicrograph script which opens all images containing a specific string in the file name.
I know how I can open an image using OpenImage( filename ) and I have seen in the documentation that a command GetFilesInDirectory() exists, which seems to be what I need. However, I do not understand how I can use this command. Can somebody give me a code snippet demonstrating this, please?
The command GetFilesInDirectory() gives you a TagList of all files / subfolders in a given directory. This is shown in the following example:
String folder
TagGroup FileList
number fFiles = 1
number fFolders = 2
If ( !GetDirectoryDialog( "Select base folder", "", folder ) )
Exit(0)
FileList = GetFilesInDirectory( folder, fFiles + fFolders )
If ( FileList.TagGroupCountTags() > 0 )
FileList.TagGroupOpenBrowserWindow( "Files & Folders", 0 )
This script will show you the resulting TagGroup in a browser window like the one below. Each list entry is itself a TagGroup which contains a single tag "Name". This tag contains the file or folder name. You can use the command to either give you only files, only subfolders, or both.
Once you have the TagGroup of all entries, you process is like any other TagGroup in DigitalMicrograph. For example, you can browse the list to read out the strings and simple print them to the results window like this:
number nTags = FileList.TagGroupCountTags()
for ( number I = 0; I < nTags; i++ )
{
TagGroup entryTG
FileList.TagGroupGetIndexedTagAsTagGroup( i, entryTG )
if ( entryTG.TagGroupIsValid() )
{
string filestr
if ( entryTG.TagGroupGetTagAsString( "Name", filestr ) )
{
Result( "\n File:" + filestr )
}
}
}

AutoIt: run a program selected with FileOpenDialog?

I need to make a script that allows a user to run a software with certain parameters (that should be typed in). So, first step, select the exe. Second, a text input box should allow the user to enter the parameters. I can't get the first step done.
I tried with the second example found here: FileOpenDialog
The only modification is a Run command I added. When I run the script, I see the complete file path for the executable but nothing runs. I don't see an error either:
include <FileConstants.au3>
include <MsgBoxConstants.au3>
Example()
Func Example()
; Create a constant variable in Local scope of the message to display in FileOpenDialog.
Local Const $sMessage = "Select a single file of any type."
; Display an open dialog to select a file.
Local $sFileOpenDialog = FileOpenDialog($sMessage, #WindowsDir & "\", "All (*.*)", $FD_FILEMUSTEXIST)
If #error Then
; Display the error message.
MsgBox($MB_SYSTEMMODAL, "", "No file was selected.")
; Change the working directory (#WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder.
FileChangeDir(#ScriptDir)
Else
; Change the working directory (#WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder.
FileChangeDir(#ScriptDir)
; Replace instances of "|" with #CRLF in the string returned by FileOpenDialog.
$sFileOpenDialog = StringReplace($sFileOpenDialog, "|", #CRLF)
; Display the selected file.
MsgBox($MB_SYSTEMMODAL, "", "You chose the following file:" & #CRLF & $sFileOpenDialog)
Run($sFileOpenDialog)
EndIf
EndFunc ;==>Example
#include <FileConstants.au3>
Example()
Func Example()
; Create a constant variable in Local scope of the message to display in FileOpenDialog.
Local Const $sMessage = "Select a single file of any type."
; Display an open dialog to select a file.
Local $sFileOpenDialog = FileOpenDialog($sMessage, #WindowsDir & "\", "All (*.*)", $FD_FILEMUSTEXIST)
If #error Then
; Display the error message.
MsgBox(1, "", "No file was selected.")
; Change the working directory (#WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder.
FileChangeDir(#ScriptDir)
Else
; Change the working directory (#WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder.
FileChangeDir(#ScriptDir)
; Replace instances of "|" with #CRLF in the string returned by FileOpenDialog.
$sFileOpenDialog = StringReplace($sFileOpenDialog, "|", #CRLF)
; Display the selected file.
MsgBox(1, "", "You chose the following file:" & #CRLF & $sFileOpenDialog)
Run($sFileOpenDialog)
EndIf
EndFunc ;==>Example
This works for me.
I dont know this "include MsgBoxConstants.au3" wich i think is unnecessary.
Lg Teifun2
You need to add the # before the include. Also the 2nd include has to be Constants.au3. When I do these changes I can successfully start any application with your code.
#include <FileConstants.au3>
#include <Constants.au3>

Elegantly appending a set of strings (.txt file) to another set of strings (.txt also)?

This request might seem slightly ridiculous, unfortunately however, it is direly needed by my small company and because of this I will be awarding the maximum bounty for a good solution.
We have a set of legacy order information stored in a .txt file. In order to import this order information into our new custom database system, we need to, for each row, append on a value from another set.
So, in my .txt file I have :
Trans Date,NorthTotal,NorthSoFar,SouthTotal,SouthSoFar,IsNorthWorkingDay,IsSouthWorkingDay
2012-01-01,21,0,21,0,0,0
2012-01-02,21,0,21,0,0,0
2012-01-03,21,1,21,1,1,1
...
Now, I have a set of locations in a .txt file also, for which I need to add two columns - city and country. Let's say :
City, Country
London,England
Paris,France
For each row in my first text file, I need to append on a row of my second text file! So, for my end result, using my sample data above, I wish to have :
Trans Date,NorthTotal,NorthSoFar,SouthTotal,SouthSoFar,IsNorthWorkingDay,IsSouthWorkingDay,City,Country
2012-01-01,21,0,21,0,0,0,London,England
2012-01-02,21,0,21,0,0,0,London,England
2012-01-03,21,1,21,1,1,1,London,England
2012-01-01,21,0,21,0,0,0,Paris,France
2012-01-02,21,0,21,0,0,0,Paris,France
2012-01-03,21,1,21,1,1,1,Paris,France
...
At the moment my only idea for this is to import both files into an SQL database and write a complicated function to append the two together (hence my tag) - surely someone can save me and think of something that will not take all day though! Please?! Thank you very much.
Edit : I am open to solutions written in all programming languages; but would prefer something which uses DOS or some kind of console/program that can be easily reran!
If you are open to using a database and importing these files (which should not be very difficult), then you do not need a "complicated function to append the two together". All you need is a simple cross join like this ... select t1.*, t2.* from t1, t2
See for yourself at... http://sqlfiddle.com/#!2/0c584/1
Here is a solution in C#. You run it like:
joinfiles a.txt b.txt c.txt
where a.txt is the first file, b.txt the second one, and c.txt the output file that will be created. It generates the output at 100 MB/s on my machine so that is probably fast enough.
using System;
using System.IO;
using System.Text;
namespace JoinFiles
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 3)
return;
string[] file1, file2;
try
{
using (var sr1 = new StreamReader(args[0]))
using (var sr2 = new StreamReader(args[1]))
{
file1 = sr1.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
file2 = sr2.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
}
using (var outstream = new StreamWriter(args[2], false, Encoding.Default, 1048576))
{
outstream.WriteLine(file1[0] + "," + file2[0]);
for (int i = 1; i < file2.Length; i++)
for (int j = 1; j < file1.Length; j++)
outstream.WriteLine(file1[j] + "," + file2[i]);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
bash script example
echo -e 'c1\na\nb' > t1
echo -e 'c2\n1\n2' > t2
while read l1;do
read -u 3 l2
echo "$l1,$l2"
done <t1 3<t2
see man bash / internal function / read
You could also write a WSH script to do this and execute from the command line. Here is a quick hack (works but will certainly need some refining). You'll need to save this as a vbs file and execute on the cli like this... wscript script.vbs infile1.txt infile2.txt outfile.txt where script.vbs is your script and infile 1 and 2 are input filenames and outfile.txt is the output file.
Set FSO_In1 = CreateObject("Scripting.FileSystemObject")
Set FSO_In2 = CreateObject("Scripting.FileSystemObject")
Set FSO_Out = CreateObject("Scripting.FileSystemObject")
Set File_Out = FSO_In1.CreateTextFile(Wscript.Arguments.Item(2),2)
Set F1_file = FSO_In1.OpenTextFile(Wscript.Arguments.Item(0),1)
HeaderWritten = False
Header = F1_File.Readline 'Read the first header line from first file
Do While F1_File.AtEndOfStream = False
F1_Line = F1_file.Readline
Set F2_File = FSO_In2.OpenTextFile(Wscript.Arguments.Item(1),1)
if HeaderWritten = False then
Header = Header & "," & F2_File.Readline
File_Out.Writeline(Header)
HeaderWritten = True
else
F2_File.Readline 'Read the first header line from second file and ignore it
end if
Do While F2_File.AtEndOfStream = False
F2_Line = F2_File.Readline
out = F1_Line & "," & F2_Line
File_Out.Writeline(out)
Loop
F2_File.Close
Loop
F1_File.Close
File_Out.Close

Groovy write to file (newline)

I created a small function that simply writes text to a file, but I am having issues making it write each piece of information to a new line. Can someone explain why it puts everything on the same line?
Here is my function:
public void writeToFile(def directory, def fileName, def extension, def infoList) {
File file = new File("$directory/$fileName$extension")
infoList.each {
file << ("${it}\n")
}
}
The simple code I'm testing it with is something like this:
def directory = 'C:/'
def folderName = 'testFolder'
def c
def txtFileInfo = []
String a = "Today is a new day"
String b = "Tomorrow is the future"
String d = "Yesterday is the past"
txtFileInfo << a
txtFileInfo << b
txtFileInfo << d
c = createFolder(directory, folderName) //this simply creates a folder to drop the txt file in
writeToFile(c, "garbage", ".txt", txtFileInfo)
The above creates a text file in that folder and the contents of the text file look like this:
Today is a new dayTomorrow is the futureYesterday is the past
As you can see, the text is all bunched together instead of separated on a new line per text. I assume it has something to do with how I am adding it into my list?
As #Steven points out, a better way would be:
public void writeToFile(def directory, def fileName, def extension, def infoList) {
new File("$directory/$fileName$extension").withWriter { out ->
infoList.each {
out.println it
}
}
}
As this handles the line separator for you, and handles closing the writer as well
(and doesn't open and close the file each time you write a line, which could be slow in your original version)
It looks to me, like you're working in windows in which case a new line character in not simply \n but rather \r\n
You can always get the correct new line character through System.getProperty("line.separator") for example.
I came across this question and inspired by other contributors. I need to append some content to a file once per line. Here is what I did.
class Doh {
def ln = System.getProperty('line.separator')
File file //assume it's initialized
void append(String content) {
file << "$content$ln"
}
}
Pretty neat I think :)
Might be cleaner to use PrintWriter and its method println.
Just make sure you close the writer when you're done
#Comment for ID:14.
It's for me rather easier to write:
out.append it
instead of
out.println it
println did on my machine only write the first file of the ArrayList, with append I get the whole List written into the file.
Kindly anyway for the quick-and-dirty-solution.

How to convert file name with path to short file name (DOS style) in Adobe AIR?

How to convert file name with path to short file name (DOS style) in Adobe AIR?
For example convert next path
"C:\Program Files\Common Files\Adobe AIR\Versions\1.0\Resources\Adobe AIR Updater.exe"
to
"C:\PROGRA~1\COMMON~1\ADOBEA~1\VERSIONS\1.0\RESOUR~1\ADOBEA~1.EXE"
Is there any algorithm?
Assuming your text portion is a string variable, you can split it by using "\" as delimiter. Then, you will have an array which you can use to check if each block is longer than 8 characters. While looping the array you can chop the last characters of each long block and put ~1. Since you're in the loop, you can progressively add to a temporary variable all these changes which will give you the final edited result at the end.
The only part that's a bit tricky is to pay attention to .exe part at the end.
So, if I were you, I'd start reading on String.split(), String.substring(), for loop, arrays
Here's my handy method that does this below:
public static string GetShortPathName(string path)
{
string[] arrPath = path.Split(System.IO.Path.DirectorySeparatorChar);
path = arrPath[0]; // drive
// skip first, ( drive ) and last program name
for (int i = 1; i < arrPath.Length - 1; i++)
{
string dosDirName = arrPath[i];
if (dosDirName.Count() > 8)
{
dosDirName = dosDirName.Substring(0, 6) + "~1";
}
path += System.IO.Path.DirectorySeparatorChar + dosDirName;
}
// include program name if any
path += System.IO.Path.DirectorySeparatorChar + arrPath[arrPath.Length - 1];
return path;
}