Sign in to follow this  
Followers 0
VelvetElvis

Issues writing to text file

21 posts in this topic

Here's a brief chunk of code that creates a text file and writes 10 lines to it.

$handle = FileOpen("D:\temp\test.txt", 1)

For $x = 1 To 10
   MsgBox(0, "", "Press OK to write line to text file.")
   If FileWriteLine($handle, "This is line " & $x) = 0 Then MsgBox(0, "Error", "Error writing to file.")
Next

Two things I'd like to know

  • If the file is deleted half-way through the loop, no error is triggered. Input continues to be written, or so it seems, but the file is no longer there. :) Why is this??
  • I'm putting together an app that captures user input (via barcode reader) to a text file. I want to make the app as bulletproof as reasonably possible. If someone deletes the text file I'm writing to half-way through a shift, a lot of time and data is lost. What's the best way to handle writing to a text file that may be open several hours? Should the file be closed after each write? (This needs to be very responsive, as scanning is very fast).

Any recommendations or text file wisdom greatly appreciated.

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Why would anyone delete such a file?

To hide the file, set the hidden attribute. Or place the file on a network share and give only read permissions to everyone but you.

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Why would anyone delete such a file?

To hide the file, set the hidden attribute. Or place the file on a network share and give only read permissions to everyone but you.

It's a busy network, with tons of users, many of which have little computer knowledge. Making the file hidden isn't an optimum solution for me.

Why does the program continue without error? Where is the data going? What's the best way around this? To be honest, I'm looking for coding solutions rather than network or file changes.

Share this post


Link to post
Share on other sites

Do you call function "FileClose($handle)" somewhere in your script? This will close the file and write the buffer to disk.

If you don't close the file and just exit the script then - I think - the buffer is just dropped.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Do you call function "FileClose($handle)" somewhere in your script? This will close the file and write the buffer to disk.

If you don't close the file and just exit the script then - I think - the buffer is just dropped.

I do prior to closing the application.

Even adding this line to the sample code I posted doesn't change the behaviour at all:

FileFlush($handle)

This is baffling to me.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

I think you will have to dive into WinAPI.au3 (comes with AutoIt) or WinAPIEX.au3 (has to be downloaded from this site) to lock the file so no one can delete it.

Edit:

Please have a look at this This opens a file without sharing.

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Thank you water.

_WinAPI_CreateFile() certainly looks like exactly what I need.

Unfortunately, after looking at the help file for all the other WinAPI functions I need to work with the files, it appears to be beyond my level of understanding,

e.g. $tBuffer = DllStructCreate("byte[" & StringLen($sText) & "]")

I was hoping once open, I could use the native AutoIt FileWriteLine() but apparently not. :)

Thanks for your efforts.

Share this post


Link to post
Share on other sites

... but I'd still like to know why my original code:

$handle = FileOpen("D:\temp\test.txt", 1)
For $x = 1 To 10
   MsgBox(0, "", "Press OK to write line to text file.")
   If FileWriteLine($handle, "This is line " & $x) = 0 Then MsgBox(0, "Error", "Error writing to file.")
Next

doesn't trigger an error when the file is deleted 1/2 way through. : :)

Share this post


Link to post
Share on other sites

That is simple.

FileWriteLine writes to the given position in a file. If the file doesn't exist, it creates the file then writes to (I believe) line 1. It is not used to detect whether the file still exists. to do that, place this before the filewriteline

If Not FileExists($Handle) Then Msgbox(0,"Error","The given file was deleted")

Share this post


Link to post
Share on other sites

That is simple. FileWriteLine writes to the given position in a file. If the file doesn't exist, it creates the file then writes to (I believe) line 1. It is not used to detect whether the file still exists. to do that, place this before the filewriteline

If Not FileExists($Handle) Then Msgbox(0,"Error","The given file was deleted")
Thanks. I figured I'd have to do that.

It's sort of at odds with my interpretation of the help file entry:

"Returns 0 if file not opened in writemode, file is read only, or file cannot otherwise be written to."

If it doesn't exist, it certainly can't otherwise be written to. :)

Share this post


Link to post
Share on other sites

VelvetElvis,

If it doesn't exist, it certainly can't otherwise be written to

Although I am far from expert in this field, I believe I can explain that. :)

You need to remember that you are probably not writing to the file, but to a buffer somewhere in memory. So AutoIt believe that the "write" was successful because that is what Windows tells it - it is too honest to think that Windows is lying barefacedly! ;)

You still have the handle value which Autoit is using to identify the file (or really buffer). If the file is deleted, the handle may well be taken over by another file - so your data could well end up being written somewhere entirely different to where you think. ;)

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

VelvetElvis,

If you use the "file exists" technique and you find that the file was deleted, than what?

If you use a "open >write>close" technique and the file is deleted, than what?

Even if you find a way to lock the file while in use and someone comes along and deletes it later, same result.

Your problem is more one of design than code.

You should do as water suggested and secure the file using access rights.

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

VelvetElvis,

Although I am far from expert in this field, I believe I can explain that. :)

You need to remember that you are probably not writing to the file, but to a buffer somewhere in memory. So AutoIt believe that the "write" was successful because that is what Windows tells it - it is too honest to think that Windows is lying barefacedly! :)

You still have the handle value which Autoit is using to identify the file (or really buffer). If the file is deleted, the handle may well be taken over by another file - so your data could well end up being written somewhere entirely different to where you think. ;)

M23

Thank you Melba23. It's a little more involved than I had envisioned. I used to write data entry apps in Delphi, using dBase files. File locking and writing was a piece of cake. I thought text files would be even easier. ;)

Share this post


Link to post
Share on other sites

VelvetElvis,

Serializing the file is one problem. The problem that you are describing is more basic, the ability to delete the file. What stopped users from deleting your dBase files?

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

VelvetElvis,

If you use the "file exists" technique and you find that the file was deleted, than what?

If you use a "open >write>close" technique and the file is deleted, than what?

Even if you find a way to lock the file while in use and someone comes along and deletes it later, same result.

If the file disappeared (and believe me, having worked in end-user support, I've seen the damage a well-meaning mouse user can do to entire directory structures by simply letting go of the left mouse button at the wrong time), at least I could cut the losses at that point, rather than the user scan for an entire shift and lose everything.

Your problem is more one of design than code.

You should do as water suggested and secure the file using access rights.

kylomas

I couldn't agree more, kylomas. I'd love to be able to lock the file write to it, then close it and release it.

Opening the file isn't a problem, I'm just struggling with the help file concerning the WinAPI functions of writing to the open file, e.g. DllStructCreate(), DllStructSetData(). These are all foreign concepts to me, and I'll have to try and figure them out.

If you or anyone else knows of an include file or wrapper someone might've written for dealing with files, I"m all ears. :)

Share this post


Link to post
Share on other sites

VelvetElvis,

Serializing the file is one problem. The problem that you are describing is more basic, the ability to delete the file. What stopped users from deleting your dBase files?

kylomas

Nothing at all.. I guess my concern is deleting it while it's being written to. A write error would show up immediately, IIRC. As well, if someone else tried opening the file to write to it, they wouldn't be able to do it if I had exclusive access. With a text file, I don't have that luxury, near as I can tell.

Hmm... maybe writing to a text file isn't such a great idea after all.

Share this post


Link to post
Share on other sites

VelvetElvis,

Something like this will serialize access to a file, however, the more users the slower shit gets. There may also be the possible of deadly embrace or what some people call spinning (two or more waits for a resource owned by some other process).

#include <winapiex.au3>
#include <date.au3>
Local $my_file = "c:tmpbar_code_data"
write("my bar code string")
Func write($str)
 While _WinAPI_FileInUse($my_file)    ;   if the file is in use
  ConsoleWrite(' file in use at ' & _now() & @lf)  ;   display message for testing
  Sleep(1000)          ; wait 1 sec
 wend            ;   and try again
 Local $hfl = FileOpen($my_file,1)    ; open for append
 FileWrite($hfl,$str)        ;   write junk
 FileClose($hfl)           ;   close the file
 $hfl = 0           ;   release the handle
endfunc

Have you considered sqlite as a DB instead of the flat files.

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

you could save a copy of the file.

write to both.

if one is deleted copy the other one and continue writing to both.

in diferent places ofcorse, even diferent drives.

Share this post


Link to post
Share on other sites

@blinky,

Yes, I was thinking that same thing as a "stop gap" solution...

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

VelvetElvis,

Something like this will serialize access to a file, however, the more users the slower shit gets. There may also be the possible of deadly embrace or what some people call spinning (two or more waits for a resource owned by some other process).

#include <winapiex.au3>
#include <date.au3>
Local $my_file = "c:tmpbar_code_data"
write("my bar code string")
Func write($str)
While _WinAPI_FileInUse($my_file)     ;   if the file is in use
  ConsoleWrite(' file in use at ' & _now() & @lf)  ;   display message for testing
  Sleep(1000)          ; wait 1 sec
wend             ;   and try again
Local $hfl = FileOpen($my_file,1)     ; open for append
FileWrite($hfl,$str)         ;   write junk
FileClose($hfl)        ;   close the file
$hfl = 0            ;   release the handle
endfunc

Have you considered sqlite as a DB instead of the flat files.

kylomas

Thanks for the code. It hasn't been decided yet what the data will be imported into, but a CSV file would be perfect input for most anything, hence my thoughts of using a text file. I'm thinking more and more that I may dump the text file and go for either Access or Excel.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0