I need to modify code written in c++. The code opens a file authfile and writes 49 bytes to it. In case the file already exists, I need to make sure the existing data will be overwritten.
The original code first deleted the file and then created a new file. For reasons beyond this discussion, I cannot delete the file, I only need to make sure it is empty, before i write new data to it.
Below is the function that writes the data. How can I modify it, so thatexisting content of the file will be overwritten ?
I suppose, I need to tchange the options of popen
bool Util::add_mcookie(const std::string &mcookie, const char *display,
const std::string &xauth_cmd, const std::string &authfile)
{
FILE *fp;
std::string cmd = xauth_cmd + " -f " + authfile + " -q";
fp = popen(cmd.c_str(), "w");
if (!fp)
return false;
fprintf(fp, "remove %s\n", display);
fprintf(fp, "add %s %s %s\n", display, ".", mcookie.c_str());
fprintf(fp, "exit\n");
pclose(fp);
return true;
}
Change popen to fopen and pclose to fclose. popen / pclose is for opening / closing a process. Also, it looks like you're creating the process with flags. You just need to give fopen the file path
Related
I have methods which returns unicode texts and i need to write them into file but some characters are not written. I have the following:
const wchar_t* getStandardText() {
return L"test";
}
const wchar_t* getUnicodeText()
{
return L"testíček";
}
int main()
{
FILE *file = fopen(FILE_NAME, "a");
fputws(getStandardText(), file);
fputws(getUnicodeText(), file);
fclose(file);
}
Output in file:
testtestí
Much more confusing for me is that some characters like "í" works and others like "č" not.
I am on Windows with VS 2015 Pro.
For reading of file i use Notepad++ which tells me the file has ANSI encoding.
This works on Windows... Change your mode parameter to have an explicit encoding...
FILE *file = fopen("foobar.txt", "a+, ccs=UTF-16LE");
OR
FILE *file = fopen("foobar.txt", "a+, ccs=UTF-8");
That appears to force the byte-order-marks (FF FE) onto the file header to indicate the file's text is Unicode.
The file has to be created with appropriate BOM. Following is the most preferred way, and make sure you're dumping only UTF-8 characters to the file. And open through notepad++ to view it.
FILE *file = fopen("test.txt", "a+, ccs=UTF-8");
I wrote a simple function to load a char * buffer from a file but when compiled through vs2017 it add rubbish at the end of the buffer but mingw compiled exe gives correct output
the function looks like something
#include <stdio.h>
#include <stdlib.h>
using namespace std;
char * loadfromfile(const char * _Filename)
{
char * buffer;
FILE * file = fopen(_Filename, "r");
if (!file)
return nullptr;
fseek(file, 0, SEEK_END);
auto _length = ftell(file);
buffer = new char[_length + 1];
rewind(file);
printf("characters read(loadformfile()) :%i\n",fread(buffer, sizeof(char), _length, file));
buffer[_length] = '\0';
fclose(file);
return buffer;
}
int main() {
char * str = loadfromfile("D:\\shutdown.bat");
printf("%s\n", (str) ? str : "failed to load");
delete[] str;
return 0;
}
VS2017 output:
characters read(loadformfile()) :86
#echo off
Set minutes=30
set /a seconds=%minutes%*60
TIMEOUT /T %seconds%
shutdown /s
\inst
g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.1.0 output:
characters read(loadformfile()) :zu
#echo off
Set minutes=30
set /a seconds=%minutes%*60
TIMEOUT /T %seconds%
shutdown /s
file is:
#echo off
Set minutes=30
set /a seconds=%minutes%*60
TIMEOUT /T %seconds%
shutdown /s
EDIT:
A working solution
char * loadfromfile(const char * _Filename)
{
char * buffer;
FILE * file = fopen(_Filename, "r");
if (!file)
return nullptr;
fseek(file, 0, SEEK_END);
auto _length = ftell(file);
buffer = new char[_length + 1];
rewind(file);
buffer[fread(buffer, sizeof(char), _length, file)] = '\0';
fclose(file);
return buffer;
}
You can't portably use fseek()/ftell() to get the size of a file.
Per the C Standard, footnote 268, p 301:
Setting the file position indicator to end-of-file, as with
fseek(file, 0, SEEK_END), has undefined behavior for a binary
stream ...
and
7.21.9.2 The fseek function
... A binary stream need not meaningfully support fseek calls with a
whence value of SEEK_END.
So you can't reliably use fseek() to get to the end of a binary file. In fact, doing so is specifically stated by the C Standard to be undefined behavior.
OK, so you can use fseek() to get to the end of a file opened in text mode, but
7.21.9.4 The ftell function
...
For a text stream, its file position indicator contains unspecified
information, usable by the fseek function for returning the file
position indicator for the stream to its position at the time
of the ftell call; the difference between two such return
values is not necessarily a meaningful measure of the number of
characters written or read.
On a text file, ftell() doesn't return a value useful in getting the file size.
In short, using fseek()/ftell() to get the size of a file is fundamentally broken. The fact that it works sometimes is just an implementation detail.
I am actually writing a c++ program that reads any kind of file and saves it as a bmp file, but first I need to read the file, and thats were the issue is
char fileName[] = "test.jpg";
FILE * inFileForGettingSize;//This is for getting the file size
fopen_s(&inFileForGettingSize, fileName, "r");
fseek(inFileForGettingSize, 0L, SEEK_END);
int fileSize = ftell(inFileForGettingSize);
fclose(inFileForGettingSize);
ifstream inFile;//This is for reading the file
inFile.open(fileName);
if (inFile.fail()) {
cerr << "Error Opening File" << endl;
}
char * data = new char[fileSize];
inFile.read(data, fileSize);
ofstream outFile;//Writing the file back again
outFile.open("out.jpg");
outFile.write(data, fileSize);
outFile.close();
cin.get();
But when I read the file, lets say its a plainttext file it allways outputs some wierd charactes at the end, for example:
assdassaasd
sdaasddsa
sdadsa
passes to:
assdassaasd
sdaasddsa
sdadsaÍÍÍ
So when I do this with a jpg, exe, etc. It corrupts it.
I am not trying to COPY a file, I know there are other ways for that, Im just trying to read a complete file byte per byte. Thanks.
EDIT:
I found out that those 'Í' are equal to the number of end lines the file has, but this doesn't help me much
This is caused by newline handling.
You open the files in text mode (because you use "r" instead of "rb" for fopen and because you don't pass ios::binary to your fstream open calls), and on Windows, text mode translates "\r\n" pairs to "\n" on reading and back to "\r\n" when writing. The result is that the in-memory size is going to be shorter than the on-disk size, so when you try to write using the on-disk size, you go past the end of your array and write whatever random stuff happens to reside in memory.
You need to open files in binary mode when working with binary data:
fopen_s(&inFileForGettingSize, fileName, "rb");
inFile.open(fileName, ios::binary);
outFile.open("out.jpg", ios::binary);
For future reference, your copy routine could be improved. Mixing FILE* I/O with iostream I/O feels awkward, and opening and closing the file twice is extra work, and (most importantly), if your routine is ever run on a large enough file, it will exhaust memory trying to load the entire file into RAM. Copying a block at a time would be better:
const int BUFFER_SIZE = 65536;
char buffer[BUFFER_SIZE];
while (source.good()) {
source.read(buffer, BUFFER_SIZE);
dest.write(buffer, source.gcount());
}
It's a binary file, so you need to read and write the file as binary; otherwise it's treated as text, and assumed to have newlines that need translation.
In your call to fopen(), you need add the "b" designator:
fopen_s(&inFileForGettingSize, fileName, "rb");
And in your fstream::open calls, you need to add std::fstream::binary:
inFile.open(fileName, std::fstream::binary);
// ...
outFile.open("out.jpg", std::fstream::binary);
I try the following where I added date and time but now nothing is written to the file. ??
QString hoho = QDate::currentDate().toString("yyyy.MM.dd") + QTime::currentTime().toString(".hh.mm.ss.zzz");
fprintf(fp, "%s timer timer3 timer5 timer6 timer7\n", hoho.toStdString().c_str());
A FILE* is normally fully buffered, meaning nothing is written to the file until the internal buffer of the FILE* is full, or until you flush the FILE* (flushing is also done when closing the file).
So flush it by adding this after the fprintf() call:
fflush(fp);
I'm trying to find a way to replace all instances of a string token in a file with another string.
How can I do this in C++ with the win32 API?
In other languages this is an easy thing to do, but in C++ I am just lost.
EDIT: For some context, this is for a WiX custom action. So portability is not a main priority, just the most simplest solution.
If the file fits in memory – it's simpler. Call OpenFile() to open file, GetFileSize() to determine file size, allocate enough memory, call ReadFile() to read file, then CloseFile. Do replacement in memory (use strstr() or similar function), then again OpenFile(), WriteFile(), CloseFile().
If the file is large - create a temporary file and read the source file in chunks and write filtered text to the temporary file, then call DeleteFile() to delete the original file and MoveFile() to move the filtered file.
You could use the Boost.Regex Library which should resemble most of the functionality you find on other platforms.
It would work like this:
In this example you’ll find how you can replace a string matching a pattern.
#include <boost/regex.hpp>
#include <string>
int main()
{
boost::regex pattern ("b.lug",boost::regex_constants::icase|boost::regex_constants::perl);
std::string stringa ("Searching for bolug");
std::string replace ("BgLug");
std::string newString;
newString = boost::regex_replace (stringa, pattern, replace);
printf("The new string is: |%s|\n",newString.c_str());
return 0;
}
but you would have of course to add the file reading/writing.
As per sharptooth's solution, I knocked up some C code to do a find and replace on a file. I used stdio calls (strlen, strstr, strcpy and strcat) to do the string manipulation (rather than win32 calls), so your only dependancy is the C run time.
This is certainly not code I would use in a production system. I would use stuff from toolkit string manipulation libraries to make this much cleaner (and not so much with the fixed length buffers). I probably wouldn't use boost, I don't like the overhead. But I figured you might like an example with just the basics (N.B. This writes the altered buffers out to .temp).
#include <stdio.h>
#define BUF_LEN 2048
int findAndReplace (const char * file, const char * find, const char * replace)
{
int replaceCount = 0;
FILE * f = fopen (file, "rt");
if (strstr(replace, find))
return 0; // replacing blah with stuff_blah_stuff
unsigned int findLen = strlen (find);
char tempFile [BUF_LEN];
strcpy (tempFile, file);
strcat (tempFile, ".temp");
FILE * writeF = fopen (tempFile, "wt");
if (!f || !writeF)
return 0;
printf ("Processing %s - %s to %s\n", file, find, replace);
char lineBuf [BUF_LEN];
memset (lineBuf, 0, BUF_LEN);
char tempLineBuf [BUF_LEN];
memset (tempLineBuf, 0, BUF_LEN);
// read each line of the file
while (fgets (lineBuf, BUF_LEN, f))
{
// get the position of find in the line buffer
char * pos = strstr (lineBuf, find);
while (pos)
{
strncpy (tempLineBuf, lineBuf, pos - lineBuf);
strcat (tempLineBuf, replace);
strcat (tempLineBuf, pos + findLen);
replaceCount++;
// replace the current buf with the replaced buffer
strncpy (lineBuf, tempLineBuf, BUF_LEN);
memset (tempLineBuf, 0, BUF_LEN);
pos = strstr (lineBuf, find);
}
printf ("writing new line %s\n", lineBuf);
fputs (lineBuf, writeF);
}
fclose (f);
fclose (writeF);
return replaceCount;
}
int main ()
{
printf ("Made %d replacements\n", findAndReplace ("blah.txt", "marker", "testing_blah"));
}
Why do you have to use the Win32 API? It's easy enough using straight C++, I wouldn't confuse the issue by adding artificial constraints. Just open your input file, open an output file, and read a line from your input. While you haven't hit EOF in your input file, use a regex to look for your token. If you find it, then replace it with your text. Write the line to the output file. Read another line from the input. When you get EOF on the input, close it. Be sure any pending output gets flushed from the output buffer. Close the output file. Done.