c programming
June 8, 2010 1:20 PM   Subscribe

C Program: How can I write a file to a specific location, say the desktop?

I want to be able to specify the name of the file, and it has a number at the end, based on how many times a loop has run, but I don't know how to get it to save to the desktop, instead of to the folder where the application exists. Here is the code I'm currently using.

FILE *pig;
char filename[15];

char s[100];
puts("Enter output file name: ");
scanf("%s", s);

sprintf_s(filename,15, "%s%d.mid", s, counter);
pig = fopen(filename, "wb");
fwrite(x, z, 1, pig);
fclose(pig);
counter++;

(x is an unsigned char array, z is how long it is, 1's the size of an unsigned char, and pig is the file)

I could use some help reading from specific locations as well, but that's not quite as important.
posted by amsterdam63 to Computers & Internet (13 answers total) 3 users marked this as a favorite
 
You need a fully-qualified path name instead of a relative file name which uses cwd. This depends on the drive/directory layout of your computer.
posted by doteatop at 1:23 PM on June 8, 2010


Since you're having the user specify the filename, perhaps you want to prepend the destination path to the user-specified name.
posted by doteatop at 1:24 PM on June 8, 2010


...and use way more than 15 characters.
...and consider using this:
sprintf_s(filename,sizeof(filename)/sizeof(char), "%s%d.mid", s, counter);
to ensure that sprintf_s always gets the right length.
posted by plinth at 1:29 PM on June 8, 2010


I presume you are running this in Windows?

The "correct" way, as far as I know, is to get the value "Desktop" under the key \\hkcu\software\microsoft\windows\currentversion\explorer\user shell folders. If you don't know how to do this, then the docs for reading registry keys can be found on MSDN.

If you just need this for you and you don't care about different users or operating systems, then the directory path is likely either

c:\documents and settings\amsterdam63\Desktop (for NT, I think, and XP)
c:\users\amsterdam63\Desktop (for Vista and Windows 7)

There's nothing wrong with a little hard-coding used in moderation.
posted by It's Never Lurgi at 1:30 PM on June 8, 2010


The "correct" way, as far as I know, is to get the value "Desktop" under the key \\hkcu\software\microsoft\windows\currentversion\explorer\user shell folders.

No. The correct way is to use SHGetSpecialFolderPath() with nFolder = CSIDL_DESKTOP. If you only want to run on Windows Vista or later, you can use Known Folders. Please don't get this sort of stuff directly out of the registry.

There's nothing wrong with a little hard-coding used in moderation.

Whenever you are hardcoding anything, make sure you do it at the top of your program in a #define or a const or similar. Inevitably, you will want some of these to be non-hard-coded at some point. Trust me.
posted by grouse at 1:44 PM on June 8, 2010 [4 favorites]


Grouse beat me to it, but here's the complete code to do this:
#include 
#include 
#include 
   
int main()
{
    char desktop_path[MAX_PATH];
    SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktop_path);
    puts(desktop_path);
    return 0;
}
Note that you'll need to link to shfolder.lib. I assume you're using visual studio, in which case you'll have to look under your project properties for where you set which libraries you link to. If you're doing it from the command line, this is all you need to do:

c:\> cl myproj.c shfolder.lib
posted by bonecrusher at 1:51 PM on June 8, 2010 [1 favorite]


Oh, for pete's sake. Let's try that again, shall we?
#include &lt windows.h&gt
#include &lt stdio.h&gt
#include &lt shlobj.h&gt
   
int main()
{
    char desktop_path[MAX_PATH];
    SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktop_path);
    puts(desktop_path);
    return 0;
}

posted by bonecrusher at 1:53 PM on June 8, 2010


You win, html!
posted by bonecrusher at 1:53 PM on June 8, 2010 [3 favorites]


On OS X and most Linux distributions you'd use either getenv("HOME"); and then append "/Desktop" or getpwnam(getenv("USER")); and then append "/Desktop." The getpw* functions are a little complicated to use, so I'd suggest the former approach. It breaks if you've redefined the $HOME environment variable (or if the desktop folder is somewhere other than ~/Desktop), but those are unlikely.
posted by jedicus at 1:56 PM on June 8, 2010


On OS X and most Linux distributions you'd use either getenv("HOME"); and then append "/Desktop" or getpwnam(getenv("USER")); and then append "/Desktop."

Not correct for OS X. You should use FSFindFolder() if you're in Carbon (and it appears that CarbonCore made it to x86_64), or in Obj-C use NSSearchPathForDirectoriesInDomains() or -[NSFileManager URLsForDirectory:inDomains:] (10.6 only).
posted by sbutler at 2:07 PM on June 8, 2010


Not correct for OS X.

He's asking a straight C-programming question, so I gave him the C standard library approach, which, by the way, will work on OS X (I just tested it).
posted by jedicus at 2:11 PM on June 8, 2010


sprintf_s(filename,sizeof(filename)/sizeof(char), "%s%d.mid", s, counter);

sizeof(char) is always 1 by definition (even on esoteric machines where bytes aren't 8 bits) so it is not necessary to divide by it here.
posted by Rhomboid at 4:44 PM on June 8, 2010


You said you could use help reading from specific locations. If you have a binary file containing data from an unsigned char array, that ought to look something like this:
int read_at_byte_index(FILE *f, int index)
{
    unsigned char value;
    if (fseek(f, index, SEEK_SET) != 0 ||
       fread(&value, 1, 1, f) != 1)
    {
        return -1;  /*  file error!  */
    }

    return (int) value;
}

I will also politely suggest that you check for error codes from your standard library calls. In particular, sprintf_s() will return -1 if the buffer is too small for your formatted filename, and fopen() will return NULL if the file can't be opened for any reason. Debugging will go a lot faster if the program tells you about those sorts of errors instead of simply failing silently...
posted by Galvatron at 8:04 PM on June 11, 2010


« Older I'm in good Company...   |   Tips for Urban Scavenger Hunt Newer »
This thread is closed to new comments.