Hello,
I am working my way through the Nim In Action book. I have been struggling with the code in Listing 3.17 on page 89.
I am using Nim 0.18 on Xubuntu Linux 18.04
import asyncdispatch, asyncfile
proc readFiles() {.async.} =
var file = openAsync("/home/profile/test.txt", fmReadWrite)
let data = await file.readAll()
echo(data)
await file.write("Hello!\n")
file.close()
waitFor readFiles()
I have played with this code in varying different ways. And every time it failed what I thought it would do by the way it reads and the way I understand the book to present it.
I pass in an existing created file with content to the readFiles() proc. I am expecting on line 4 for it to display on the screen the contents of the file. It never does. It is also what the book describes it to do "Displays the contents of the file".
In actuality it does as described. But what is not present is the knowledge that the line with openAync in fmReadWrite mode is going to truncate your file to 0 bytes so that there is no data to display. It wiped out my file every single time.
I naively understood from the way the code reads and the description of the code that data was going to be displayed.
Now this code as to what I have seen before is never executed in the book. I am trying things as I go.
So I went and dug into the source trying to find out why it does not do what I expected. I still have not seen in the source where it says that fmReadWrite truncates the files to 0.
So I went to Python docs for their open('filename', 'mode') function. They explicitly say:
Character Meaning 'r' open for reading (default) 'w' open for writing, truncating the file first 'x' open for exclusive creation, failing if the file already exists 'a' open for writing, appending to the end of the file if it exists 'b' binary mode 't' text mode (default) '+' open a disk file for updating (reading and writing)
The 'w' matched my experience with fmReadWrite mode.
In the source I did see the fmReadWriteExisting mode. When I changed my code to use that instead. Everything then worked as the code read and as I expected.
I don't know what I could have done differently. I am open to learning. I just wanted to write my experience and hopefully help someone else like me who does not have explicit knowledge of OS level filesystem calls and that fmWrite, fmReadWrite will create or truncate and that if you expect to readWrite without truncation use fmReadWriteExisting. If I am in error on any of these details. Please let me know.
I am experienced mainly in dynamic higher level languages like Smalltalk and Python. Nim is my first static compiled, static typed language. I have some learning to do to get comfortable. But I think it will be worth the effort.
Thanks for the book and for Nim.
Listing 3.17 on page 89.
Well, if that is the code from the book, you may have indeed found a typo.
It is not too surprising that mode readWrite clears the content. And that mode is well documented for system module:
Great. I am glad it is documented and that I simply have not acquired my way around the Nim docs or the Nim language.
I searched for fmReadWrite and did not find much. I searched openAsync and read the source. But I do not find anything that leads me to the FileMode enum.
It simply speaks of mode = fmRead.
However there are a few procedures above which list FileMode. When I have better Nim language reading skills. I could have probably navigated my way through to FileMode so that I could have done a search for it. Then I would have found what you linked.
Thanks for the replies. I look forward to continuing to learn Nim!
Really liking this new forum. Great job!
In an effort to learn how to be a good citizen of the Nim community. I have made a Pull Request with a simple change to openAsync
proc openAsync*(filename: string, mode = fmRead): AsyncFile =
## Opens a file specified by the path in ``filename`` using
- ## the specified ``mode`` asynchronously.
+ ## the specified FileMode ``mode`` asynchronously.
when defined(windows) or defined(nimdoc):
let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
let desiredAccess = getDesiredAccess(mode)
I have never made a pull request before. And do not know if you want PRs on something like this. Or even if I did it correctly. I am agreeable for you all to accept or reject the PR. It isn't significant and fixes nothing.
Let me know. I am open to learn.
Also, is adding something to the index something than someone like myself can learn to do? Is it something that is open to community help?
Thanks.