COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 05-06-2014, 04:44 AM   #1
stw
Human being with feelings
 
stw's Avatar
 
Join Date: Apr 2012
Posts: 279
Default Basic file io

My next challenge is to prepare my plug for some basic file reads and writes to handle user data.
Unfortunately my trials with standard input/output classes failed. Since i couldn't find any examples on how to deal with that in wdl i'd like to ask if i may have overlooked something. If not maybe someone could pass me some basic information?
stw is offline   Reply With Quote
Old 05-06-2014, 04:56 AM   #2
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by stw View Post
My next challenge is to prepare my plug for some basic file reads and writes to handle user data.
Unfortunately my trials with standard input/output classes failed. Since i couldn't find any examples on how to deal with that in wdl i'd like to ask if i may have overlooked something. If not maybe someone could pass me some basic information?
While I would usually advocate using the C++ standard library for many tasks, file I/O tends to be a sore point where it IMHO just doesn't work well. WDL has the WDL_FileRead and WDL_FileWrite classes (fileread.h and filewrite.h) that might work better. Of course, as usual, no obvious example code exists on how to use them.

If you'd like, I can try writing some code that uses those WDL classes? It would be helpful to know what kind of data exactly you need to write and read, though...
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 05-06-2014, 05:06 AM   #3
stw
Human being with feelings
 
stw's Avatar
 
Join Date: Apr 2012
Posts: 279
Default

Quote:
Originally Posted by Xenakios View Post
While I would usually advocate using the C++ standard library for many tasks, file I/O tends to be a sore point where it IMHO just doesn't work well. WDL has the WDL_FileRead and WDL_FileWrite classes (fileread.h and filewrite.h) that might work better. Of course, as usual, no obvious example code exists on how to use them.

If you'd like, I can try writing some code that uses those WDL classes? It would be helpful to know what kind of data exactly you need to write and read, though...
HI Xenakios,
thanks for the hint. The WDL File classes should be my staring point then. I'll take a look into them.
I just need some very basic string i/o. The goal is to store some controller data and registration files which hopefully shouldn't be that hard to accomplish.
But anyway as i said in another thread any working example is worth thousands of lines of theory. If you like to give it a spin you're greatly welcomed! :-)
stw is offline   Reply With Quote
Old 05-06-2014, 11:52 AM   #4
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Looks like the WDL file classes are not designed to help dealing with text data...Writing is fairly trivial, but reading requires more careful handling...

Writing is like :

Code:
        WDL_FileWrite outfile("C:\\ssd_tests\\wdl_test_file.txt");
        if (outfile.IsOpen()==true)
        {
            std::string txt1("Foo\n");
            outfile.Write(txt1.data(),txt1.size());
            std::string txt2("Bar\n");
            outfile.Write(txt2.data(),txt2.size());
        } else std::cout << "could not open file for writing\n";
Reading would start something like :

Code:
        WDL_FileRead infile("C:\\ssd_tests\\wdl_test_file.txt");
        if (infile.IsOpen()==true)
        {
            std::vector<char> buffer(infile.GetSize()+1); // +1 to have space for the terminating zero
            infile.Read(buffer.data(),infile.GetSize());
            buffer[infile.GetSize()]='\0'; // put in the string terminating zero
But I think I will leave the rest (parsing newlines etc) as an exercise for the reader...(No pun intended.)

If you need to handle text files, perhaps the C++ standard library facilities might be worth looking into again, after all...What kinds of problems did you encounter while trying to use them? (My own pains with ifstream and ofstream have mostly been when trying to use them for binary files, such as wav-files etc...For text files they may work tolerably enough.)
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.

Last edited by Xenakios; 05-06-2014 at 12:00 PM.
Xenakios is offline   Reply With Quote
Old 05-06-2014, 01:17 PM   #5
stw
Human being with feelings
 
stw's Avatar
 
Join Date: Apr 2012
Posts: 279
Default

Quote:
Originally Posted by Xenakios View Post
If you need to handle text files, perhaps the C++ standard library facilities might be worth looking into again, after all...What kinds of problems did you encounter while trying to use them? (My own pains with ifstream and ofstream have mostly been when trying to use them for binary files, such as wav-files etc...For text files they may work tolerably enough.)
Hi Xenakios,
thanks for your examples. I'll try to deal with these later.
However when i first tried the standard file i/o libs i was on OSX and got several errors just by including the libs and use of basic codings. I guessed that maybe there should be some special treatment for the WDL lib.
After your advise to look into it again i did the same on my Win OS and could successful do what failed before. So either i definitely did something wrong in my first approach on OSX or there might be platform dependent differences. If i had to guess the voting clearly goes to users (my) failure. ;-)
I'll take the OSX challenge again tomorrow and hopefully it works as good as now.
Again thanks for helping :-)
stw is offline   Reply With Quote
Old 05-06-2014, 01:39 PM   #6
olilarkin
Human being with feelings
 
Join Date: Apr 2009
Location: Berlin, Germany
Posts: 1,248
Default

although you should get the hang of reading and writing to files with stdio.h first, for storing simple preferences you should check out swell-ini.cpp in WDL which allows you to use the windows WritePrivateProfileString / GetPrivateProfileString methods on OSX to read/write a .ini file . That is what i am using for global preferences in my latest plugin. The WDL-OL standalone app wrapper uses it to store info about the audio interface etc.
__________________
VirtualCZ | Endless Series | iPlug2 | Linkedin | Facebook
olilarkin is offline   Reply With Quote
Old 05-06-2014, 01:47 PM   #7
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by olilarkin View Post
although you should get the hang of reading and writing to files with stdio.h first
You mean the ancient crap like fopen, fwrite and fread...? Why? Those are so badly suited to be used in robust C++ code that they need proper C++ class wrappers anyway, in which case it is best to just use something that has already been written and tested...
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 05-06-2014, 02:04 PM   #8
olilarkin
Human being with feelings
 
Join Date: Apr 2009
Location: Berlin, Germany
Posts: 1,248
Default

you're right - it just sounded like the OP was stuck with the basics of file i/o using the standard C/C++ libraries (i may have imagined this), so i thought it might be worth learning how those work before moving on.
__________________
VirtualCZ | Endless Series | iPlug2 | Linkedin | Facebook
olilarkin is offline   Reply With Quote
Old 04-07-2017, 04:40 PM   #9
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
Default

Quote:
Originally Posted by Xenakios View Post
Code:
        WDL_FileWrite outfile("C:\\ssd_tests\\wdl_test_file.txt");
        if (outfile.IsOpen()==true)
        {
            std::string txt1("Foo\n");
            outfile.Write(txt1.data(),txt1.size());
            std::string txt2("Bar\n");
            outfile.Write(txt2.data(),txt2.size());
        } else std::cout << "could not open file for writing\n";
How would I use this to write a file to Reaper's resource path ?

I've tried
Code:
char buf[1024];
strcpy(buf, GetResourcePath());
strcpy(buf, "wdl_test_file.txt");
WDL_FileWrite outfile(buf); 

if (outfile.IsOpen() == true)
....
It kinda half-works, i.e. a file is written, but it's not in Reaper's resource path.
I guess my non-knowledge about C strings comes to light again here...

edit:
Forgot to mention, this is in SWS extensions, so GetResourcePath() works, I can see when I set a breakpoint, I'm having trouble with the string concatenation obviously.

Last edited by nofish; 04-07-2017 at 05:00 PM.
nofish is offline   Reply With Quote
Old 04-07-2017, 05:25 PM   #10
ynohtna
Human being with feelings
 
Join Date: Jan 2014
Location: Brighton, UK
Posts: 21
Default

Your second call to strcpy overwrites your buffer contents (the result of GetResourcePath()) with "wdl_test_file.txt" because it's using strcpy again.

That second call should be using strcat instead. I'm sure you'll work out why if you look up the docs for strcpy & strcat.
ynohtna is offline   Reply With Quote
Old 04-07-2017, 05:35 PM   #11
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by ynohtna View Post
Your second call to strcpy overwrites your buffer contents (the result of GetResourcePath()) with "wdl_test_file.txt" because it's using strcpy again.

That second call should be using strcat instead. I'm sure you'll work out why if you look up the docs for strcpy & strcat.
Or just use snprintf...

Code:
char buf[4096]; // might not be enough for extreme cases but enough for most cases...
snprintf(buf,sizeof(buf),"%s/testfile.txt", GetResourcePath());
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 04-07-2017, 05:40 PM   #12
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by nofish View Post
I guess my non-knowledge about C strings comes to light again here...
Please try to avoid using raw C strings in C++ code if in any way possible...Pretty much anything available in C++ will be better than that. WDL_String would be worth looking into in WDL/SWS context.

If you have other functions/classes that want raw C strings as arguments, WDL_String has the Get() method to get the raw char* C string buffer. There may sometimes however be cases where using a C++ string wrapper will not work, but most code should not be written considering those pathological cases.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.

Last edited by Xenakios; 04-07-2017 at 05:47 PM.
Xenakios is offline   Reply With Quote
Old 04-07-2017, 05:57 PM   #13
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
Default

I have to read up on both strcat (what I was actually looking for I guess) and snprintf, but it works now, thanks !

Quote:
Please try to avoid using raw C strings in C++ code if in any way possible...Pretty much anything available in C++ will be better than that. WDL_String would be worth looking into in WDL/SWS context. (If you have other functions/classes that want raw C strings as arguments, WDL_String has the Get() method to get the raw char* C string buffer.)
Ok, but let's take GetResourcePath() as example, it returns a pointer to a C string (as I gather), how could I avoid using C strings there ?

edit:
Too tired for thinking currently, will revisit it tomorrow. Anyway, I appreciate the help, thanks again.

Last edited by nofish; 04-07-2017 at 06:09 PM.
nofish is offline   Reply With Quote
Old 04-07-2017, 06:22 PM   #14
earlevel
Human being with feelings
 
Join Date: Dec 2015
Posts: 331
Default

Quote:
Originally Posted by nofish View Post
I have to read up on both strcat (what I was actually looking for I guess) and snprintf...
Sorry to be a pain and add another wrinkle, but if you need to read up on snprintf, do yourself a favor and read up on ostringstream instead. Not only will you be working the c++ way for now and the future, but you'll be avoiding a deprecated (in MS Visual Studio C++) function. Bypass the printf legacy altogether.
earlevel is offline   Reply With Quote
Old 04-07-2017, 06:33 PM   #15
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by nofish View Post
Ok, but let's take GetResourcePath() as example, it returns a pointer to a C string (as I gather), how could I avoid using C strings there ?
Sane C++ string classes allow using char* or const char* as parameters in their suitable methods.

For example with WDL_String :
Code:
WDL_String s;
s.SetFormatted(4096, "%s/test.txt",GetResourcePath());
or
Code:
WDL_String s(GetResourcePath());
s.Append("/test.txt");
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.

Last edited by Xenakios; 04-07-2017 at 06:41 PM.
Xenakios is offline   Reply With Quote
Old 04-08-2017, 01:07 AM   #16
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
Default

I've seen use of WDLString in SWS code but didn't have a closer look yet.
This simplifies matters, thanks.

Last edited by nofish; 04-08-2017 at 01:32 AM.
nofish is offline   Reply With Quote
Old 09-16-2019, 10:42 AM   #17
Nonlinear
Human being with feelings
 
Join Date: Apr 2018
Posts: 396
Default

Per Xenakios' example above I have tried the following in my constructor with no success:

Code:
        WDL_FileWrite outfile("C:\\Documents\\plugin_test_file.txt");
  	if (outfile.IsOpen() == true)
	{
		std::string txt1("Test\n");
		outfile.Write(txt1.data(), txt1.size());
		std::string txt2("Text\n");
		outfile.Write(txt2.data(), txt2.size());
	}
It compiles without error but doesn't create a file nor does it write anything to a file that already exists. What am I missing?
Nonlinear is offline   Reply With Quote
Old 09-16-2019, 12:05 PM   #18
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by Nonlinear View Post
What am I missing?
Quite hard to say, that still works here...Are you sure the code is actually executed? (Running the latest build of the plugin, you put the code into a constructor that is actually executed etc...?) Is the file path right? Do you have write permissions in that folder?
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 09-16-2019, 12:39 PM   #19
Nonlinear
Human being with feelings
 
Join Date: Apr 2018
Posts: 396
Default

Quote:
Originally Posted by Xenakios View Post
Quite hard to say, that still works here...Are you sure the code is actually executed? (Running the latest build of the plugin, you put the code into a constructor that is actually executed etc...?) Is the file path right? Do you have write permissions in that folder?
Ah - permissions prevented writing to the path I used (how are other plugin installers writing there??).

Now, what is the difference/advantage of using WDL_FileRead/Write vs. std::fstream?
Nonlinear is offline   Reply With Quote
Old 09-16-2019, 02:07 PM   #20
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by Nonlinear View Post
Now, what is the difference/advantage of using WDL_FileRead/Write vs. std::fstream?
I would make a guess the WDL classes have more performant buffering etc settings than the std::fstream stuff has by default. The std::fstream stuff can be quite slow for dealing with large amounts of data unless you change the buffering settings etc...
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 07:11 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.