how can i prevent my record from overwrite c++
cin.get (terminator);
FILE * dat = fopen("Accounts.dat", "wb");
myAccount.username = myUsername;
myAccount.password = myPassword;
int n = 0;
int filenumber=0;
filenumber= n;
fseek(dat,sizeof(myAccount), ios_base :: end);
fwrite(&myAccount, sizeof(myAccount),ios_base ::app, dat);
fclose (dat);
Some theory: fseek is a C routine found in stdio.h ( <cstdio> in C++). It works with C file descriptors as in the following
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ("myfile.txt","w");
if (pFile!=NULL)
{
fseek ( pFile , 0 , SEEK_SET );
fputs ("fopen example",pFile);
fclose (pFile);
}
return 0;
}
Notice the SEEK_SET flag used with fseek.
ios_base::end and similar are C++ member constants used in conjunction of the <fstream> routines as in the following
#include <fstream> // std::fstream
int main () {
std::fstream fs;
fs.open ("test.txt", std::fstream::in | std::fstream::out | std::fstream::app);
fs << " more lorem ipsum";
fs.close();
return 0;
}
You should NEVER mix those at any time, it's not typesafe and even if it works there's no guarantee that it would, plus it's not portable and a terrible code practice as well.
There isn't much one could deduce from your small snippet, but if you're encountering weird or erroneous behavior, you should first check these notions out.
References:
http://www.cplusplus.com/reference/cstdio/fseek/
http://www.cplusplus.com/reference/fstream/fstream/open/
Do not mix FILE* with std::fstream. Use one or the other.
std::fstream File("Accounts.dat", std::ios::out | std::ios::binary | std::ios::app);
if (File.is_open())
{
File.write(reinterpret_cast<char*>(&myAccount), sizeof(myAccount));
File.close();
}
or if using C:
FILE* file = fopen("meh.dat", "ab+");
if (file)
{
fwrite(&myAccount, sizeof(myAccount), 1, file);
fclose(file);
}
Related
I'm trying to write a string into a file, but I don't know how to do it, I have tried to use wstring instead of string in my randomString() string function, and other things just to write a string to a file.
The if condition is checking if file is created, and if yes, write to it.
fopen is used to open the file, path1 variable is the path to my file, and the "w" is equal to write.
randomString() is a string function.
char buffer[100] = { randomString() };
FILE* file;
file = fopen(path1, "w");
if (file) {
fwrite(buffer, sizeof(char), sizeof(buffer), file);
fclose(file);
}
return;
If you're using a new-ish compiler you can try std::filesystem
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
auto directoryToWriteTo = fs::current_path(); // returns a fs::path object
std::ofstream fileStream(directoryToWriteTo.string() + "/nameOfYourFile.txt");
if(fileStream.is_open())
fileStream << "Whatever string you want to write to a file\n";
}
std::filesystem isn't needed for writing to one file, but it does make things like iterating over all files in a directory easy, as adapted from the cppreference.com examples.
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
auto directoryToTraverse = fs::current_path();
for(auto& p: fs::directory_iterator(directoryToTraverse)){
if(fs::is_regular_file(p)){
std::ofstream tmpStream(p,std::ios_base::app); //open file in append mode
tmpStream << "Append a string to each regular file in your directory\n";
}
}
}
It also allows one to change file permissions programmatically with standard c++.
If you are just trying to print out to a file the contents of a string, using fwrite, then you need to do something like the following
std::string str = randomString();
if ( file ) {
fwrite( str.c_str(), sizeof( char ), str.size(), file );
fclose( file );
}
Since fwrite expects the first parameter to be void *, an std::string is not compatible; however, a char * is. By calling .c_str() on the string, you would have a char * to work with. The second parameter is the size of the type, which for a std::string is char, so sizeof( char ) gives the size (which is 1). The third parameter is the count (number of characters to write), which can easily be gotten from str.size().
i don't know whats the problem with filesystem resize_file standart c++ 17 in visual studio. when i test the STL with manual. it can resize as expect. when using in conditional. its like a bug. the result output is split 2 parts. i test it a file 2MB size. the result i should expected is input file should be resize to 0 byte in the end.
std::ifstream input("D:/input.exe", std::ios::binary);
if (input.is_open())
{
std::ofstream output("D:/output.exe", std::ios::binary | std::ios::ate | std::ios::app);
auto p = std::filesystem::path("D:/input.exe");
std::vector<char> buffer(1048576);
do
{
long long setPosition;
if (std::filesystem::file_size(p) > buffer.size())
{
setPosition = (std::filesystem::file_size(p) - buffer.size());
input.seekg(setPosition);
}
else
{
input.seekg(0);
}
input.read(buffer.data(), buffer.size());
std::streamsize dataSize = input.gcount();
if (dataSize)
{
output.seekp(0);
output.write(buffer.data(), dataSize);
long long resizeFile = (std::filesystem::file_size(p) - dataSize);
std::filesystem::resize_file(p, resizeFile);
}
else
{
output.close();
input.close();
break;
}
} while (true);
}
else
{
std::cout << "File is not exist";
}
What you are trying to do will not work. resize_file will truncate the file at the end of the file, so when you read X bytes from the start of the file and then truncate the file, you will chop off X bytes at the end of the file. You will probably end up with both input.exe and output.exe containing the beginning of the original input.exe. What you should do is to truncate the file after you've read it. The below will make output.exe a copy of the original input.exe and input.exe will be 0 bytes.
#include <iostream>
#include <fstream>
#include <filesystem>
int main() {
auto p = std::filesystem::path("D:/input.exe");
std::ifstream input(p, std::ios::binary);
if (input)
{
std::ofstream output("D:/output.exe", std::ios::binary);
std::vector<char> buffer(1048576);
while (true) {
input.read(buffer.data(), buffer.size());
std::streamsize dataSize = input.gcount();
if (dataSize==0) break;
output.write(buffer.data(), dataSize);
}
std::filesystem::resize_file(p, 0);
}
else
{
std::cout << "File does not exist";
}
}
I have a problem with the following code:
#include <iostream>
#include <stdio.h>
#include "ISBNPrefix.h"
using namespace std;
int main() {
FILE* file = NULL;
int area = 0, i = 0;
long s;
file = open("swagger.txt");
fscanf(file, "%ld", &s);
cout << s << endl;
}
and here's ISBNPrefix.cpp:
#include <iostream>
#include <stdio.h>
#include "ISBNPrefix.h"
using namespace std;
FILE* open(const char filename[]) {
FILE* file = NULL;
file = fopen("filename", "r");
if (file != NULL)
return file;
else return NULL;
}
my ISBNPrefix.h
FILE* open (const char filename[]);
And the content of swagger.txt is: 123456789
When I try to run it to test if it copies the 123456789 into my variable i get a segmentation fault!
You have problem in your function for opening a file:
FILE* open(const char filename[]) {
FILE* file = NULL;
file = fopen("filename", "r"); <-- here
it should be file = fopen(filename, "r");
Also you designed open function to return NULL if there is no file, but then you don't check its return value once you call it:
file = open("swagger.txt");
if (file == NULL) ... <-- you should check the return value
fscanf(file, "%ld", &s);
Also note that fopen and fscanf are C-style functions. Since you are using C++, there are other more convenient means how to read data from a file. Have a look at std::ifstream. Also when you work with C headers in C++, you should include their C++ wrappers: cstdio, cstdlib, etc.
You need fopen for a start. Where does ISBNPrefix.cpp come into the picture?
Several topics (see Using C++ filestreams (fstream), how can you determine the size of a file? and C++: Getting incorrect file size) on how to measure a file size compute the difference between the beginning and the end of the file like that :
std::streampos fileSize( const char* filePath ){
std::streampos fsize = 0;
std::ifstream file( filePath, std::ios::binary );
fsize = file.tellg();
file.seekg( 0, std::ios::end );
fsize = file.tellg() - fsize;
file.close();
return fsize;
}
But instead of opening the file at the beginning, we can open it at the end and just take a measure, like that :
std::streampos fileSize( const char* filePath ){
std::ifstream file( filePath, std::ios::ate | std::ios::binary );
std::streampos fsize = file.tellg();
file.close();
return fsize;
}
Will it work ? And if not why ?
It should work just fine. The C++ standard says about std::ios::ate
ate - open and seek to end immediately after opening
There's no reason it would fail when a manual open-then-seek would succeed. And tellg is the same in either case.
I'm trying to join two big files (like the UNIX cat command: cat file1 file2 > final) in C++.
I don't know how to do it because every method that I try it's very slow (for example, copy the second file into the first one line by line)
¿What is the best method for do that?
Sorry for being so brief, my english is not too good
If you're using std::fstream, then don't. It's intended primarily for formatted input/output, and char-level operations for it are slower than you'd expect. Instead, use std::filebuf directly. This is in addition to suggestions in other answers, specifically, using the larger buffer size.
Use binary-mode in the standard streams to do the job, don't deal with it as formatted data.
This is a demo if you want transfer the data in blocks:
#include <fstream>
#include <vector>
std::size_t fileSize(std::ifstream& file)
{
std::size_t size;
file.seekg(0, std::ios::end);
size = file.tellg();
file.seekg(0, std::ios::beg);
return size;
}
int main()
{
// 1MB! choose a conveinent buffer size.
const std::size_t blockSize = 1024 * 1024;
std::vector<char> data(blockSize);
std::ifstream first("first.txt", std::ios::binary),
second("second.txt", std::ios::binary);
std::ofstream result("result.txt", std::ios::binary);
std::size_t firstSize = fileSize(first);
std::size_t secondSize = fileSize(second);
for(std::size_t block = 0; block < firstSize/blockSize; block++)
{
first.read(&data[0], blockSize);
result.write(&data[0], blockSize);
}
std::size_t firstFilerestOfData = firstSize%blockSize;
if(firstFilerestOfData != 0)
{
first.read(&data[0], firstFilerestOfData);
result.write(&data[0], firstFilerestOfData);
}
for(std::size_t block = 0; block < secondSize/blockSize; block++)
{
second.read(&data[0], blockSize);
result.write(&data[0], blockSize);
}
std::size_t secondFilerestOfData = secondSize%blockSize;
if(secondFilerestOfData != 0)
{
second.read(&data[0], secondFilerestOfData);
result.write(&data[0], secondFilerestOfData);
}
first.close();
second.close();
result.close();
return 0;
}
Using plain old C++:
#include <fstream>
std::ifstream file1("x", ios_base::in | ios_base::binary);
std::ofstream file2("y", ios_base::app | ios_base::binary);
file2 << file1.rdbuf();
The Boost headers claim that copy() is optimized in some cases, though I'm not sure if this counts:
#include <boost/iostreams/copy.hpp>
// The following four overloads of copy_impl() optimize
// copying in the case that one or both of the two devices
// models Direct (see
// http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4)
boost::iostreams::copy(file1, file2);
update:
The Boost copy function is compatible with a wide variety of types, so this can be combined with Pavel Minaev's suggestion of using std::filebuf like so:
std::filebuf file1, file2;
file1.open("x", ios_base::in | ios_base::binary);
file2.open("y", ios_base::app | ios_base::binary);
file1.setbuf(NULL, 64 * 1024);
file2.setbuf(NULL, 64 * 1024);
boost::iostreams::copy(file1, file2);
Of course the actual optimal buffer size depends on many variables, 64k is just a wild guess.
As an alternative which may or may not be faster depending on your file size and memory on the machine. If memory is tight, you can make the buffer size smaller and loop over the f2.read grabbing the data in chunks and writing to f1.
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
ofstream f1("test.txt", ios_base::app | ios_base::binary);
ifstream f2("test2.txt");
f2.seekg(0,ifstream::end);
unsigned long size = f2.tellg();
f2.seekg(0);
char *contents = new char[size];
f2.read(contents, size);
f1.write(contents, size);
delete[] contents;
f1.close();
f2.close();
return 1;
}