I think this should be quite simple, but my googling didn't help so far... I need to write to an existing file in C++, but not necessarily at the end of the file.
I know that when I just want to append text to my file, I can pass the flag ios:app when calling open on my stream object. However, this only let's me write to the very end of the file, but not into its middle.
I made a short program to illustrate the issue:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
string path = "../test.csv";
fstream file;
file.open(path); // ios::in and ios::out by default
const int rows = 100;
for (int i = 0; i < rows; i++) {
file << i << "\n";
}
string line;
while (getline(file, line)) {
cout << "line: " << line << endl; // here I would like to append more text to certain rows
}
file.close();
}
You cannot insert in the middle of the file. You have to copy the old file to a new file and insert whatever you want in the middle during copying to the new file.
Otherwise, if you intend to overwrite data/lines in the existing file, that is possible by using std::ostream::seekp() to identify the position within the file.
You could write to the end and swap lines until it ends up in the right position.
Here's what I had to do.
Here's the test.txt file before:
12345678
12345678
12345678
12345678
12345678
Here's a sample of my program
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
fstream& goToLine(fstream& file, int line){
int charInLine = 10; //number of characters in each line + 2
//this file has 8 characters per line
int pos = (line-1)*charInLine;
file.seekg(pos);
file.seekp(pos);
return file;
}
fstream& swapLines(fstream& file, int firstLine, int secondLine){
string firstStr, secondStr;
goToLine(file,firstLine);
getline(file,firstStr);
goToLine(file,secondLine);
getline(file,secondStr);
goToLine(file,firstLine);
file.write(secondStr.c_str(),8); //Make sure there are 8 chars per line
goToLine(file,secondLine);
file.write(firstStr.c_str(),8);
return file;
}
int main(){
fstream file;
int numLines = 5; //number of lines in the file
//open file once to write to the end
file.open("test.txt",ios::app);
if(file.is_open()){
file<<"someText\n"; //Write your line to the end of the file.
file.close();
}
//open file again without the ios::app flag
file.open("test.txt");
if(file.is_open()){
for(int i=numLines+1;i>3;i--){ //Move someText\n to line 3
swapLines(file,i-1,i);
}
file.close();
}
return 0;
}
Here's the test.txt file after:
12345678
12345678
someText
12345678
12345678
12345678
I hope this helps!
Based on my basic knowledge of Operating systems, I would say it is not possible.
I mean it is not impossible to make an OS that can allow such functionality with current storage technologies, but doing so would always lead to wastage of space in segments.
But I am not aware of any technology that can allow that. Although some cloud-based DataBases do use such kinds of functionally (like inserting content in middle of a file), but they are made specifically for that DBMS software, with very specifically targeted hardware, and they may also have some custom-built kernels to perform such tasks.
Related
I'm trying to have the code read and repeat the last line of text in an input file, and put an underscore line right below it. As the code is, it will cout the last line to the terminal but won't output anything to the file. If I remove the while(getline()), the underscore line will appear but then it can't find the line string.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string underscoreDiv (int lengthText){
string underscores;
for(int i{}; i<lengthText; i++)
{
underscores += "_";
}
return underscores + "\n";
}
int main(){
fstream fileApp("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt", ios::in | ios::app);
if(fileApp.is_open()){
string underscore;
string line;
underscore=underscoreDiv(80);
while(getline(fileApp, line)){} ///removing this line
cout<<line;
fileApp<<"\n"<<line<<endl;
fileApp<<underscore<<endl;
fileApp.close();
}
else{
cout<<"Text file not file";
}
system("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt");
return 0;
}
I wrote this modified code that reads the last line and prints it and then prints the underscore line but I'm having to open, close, then reopen the input file which makes it too slow.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string underscoreDiv (int lengthText){
string underscores;
for(int i{}; i<lengthText; i++)
{
underscores += "_";
}
return underscores + "\n";
}
int main(){
fstream fileApp("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt", ios::app | ios::in);
string underscore;
string line;
if(fileApp.is_open()){
underscore=underscoreDiv(80);
while(getline(fileApp, line)){}
cout<<line;
fileApp<<"\n"<<line<<endl; ///these 2 lines don't do anything
fileApp<<underscore<<endl;
fileApp.close();
}
else{
cout<<"Text file not file";
}
fileApp.open("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt", ios::app | ios::in);
fileApp<<"\n"<<line<<endl;
fileApp<<underscore<<endl;
///system("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt"); ///too lazy to write a close statement here.
return 0;
}
The problem that you encounter has to do with the state of the stream. After each IO operation the result of that operation is stored in internhal state bits of the stream.
There is a very good overview in the CPP reference here. Please especially look at the table at the bottom of this page.
After the execution of the loop while(getline(fileApp, line)){} the eof bit of the stream is set. And only because of that, the while loop stops. Look in the table. If the eof bit is set, the bool function will return false. And since the while-loop excpects a boolean value, the bool function of the stream (that will be returned by std::getline) will be called.
So, now that we reached the end of the file, the stream is in fail state.
And then, no further IO operation on this stream will be executed.
Solution: Call the streams clear function after your while loop: fileApp.clear();
Recommendation: In general you should always check the state of a stream after IO operations.
This is my first post and I'm fairly new to C++. I am currently looking for a way to save multiple variables to a file (XML or TXT) so it looks like this:
charactername:George
level:5
I would also like to be able to read these and put them into a variable.
Ex:
std::string characterName = "George";
(but it would read George from the line in the file charactername:George)
I have a total of 68 variables (48 strings, 11 ints, and 9 bools) I want in 1 file.
Does anyone know a way to do this or a tutorial they could point me towards? I have found was to save 1 string to a file, but not multiple variables of different types.
I think you should learn how to use a datafile matrix,
But before that here is some basic file management code for you to try use, you'll be able to read in data and recover it based on a structured layout, when recovering your bool data use an implicit conversion to change from a string.
Here are some basic file operations, this will create a txt file that has data on new lines:
// basic file operations
// writing on a text file
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile ("example.txt");
if (myfile.is_open())
{
myfile << "This is a line.\n";
myfile << "This is another line.\n"; // this will for data onto a new line to be read later.
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
How to recover data, this will put the data into a string array which you can then use to recall data from in your code:
// how to retrieve the data:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
string line, data_array[67];
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
data_array[i] = line; i++;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
How to edit data, you'll need to have a function to read in all your variables and rewrite the whole text file as unless each line is exactly the same byte you can not jump directly to it.
To look more into detail you should learn how to use a datafile matrix, here are some nice videos to get you started.:
C++ Tutorial (Reading Rows and Columns from datafile Matrix
Matrix in C++ | Part #1 | simple matrix definition using arrays
I am unable to read '.dat' file. I have tired all the possible ways and tired googling it but I could not find the solution. All it gives me is a null value for integer and a junk value for a string variable or char. This what I have written
ifstream file;
file.open("data1.dat"); // I have also tried this way too like file.open("data1.dat", ios::binary, ios::in);
int data=0;
file >> data;
cout << data << endl;
system("pause");
return 0;
I am using visual studio to compile this code. I am pretty sure that the pointer is entering into the data file but I don't know for what reason the data is not being read.
The .dat file consists of integer number per line ranging from 0, so I just need to read the file and get number from each line and should find the sum of all numbers in the file. The file contains number like
5,
468,
3200,
32, etc.,. Each number is in a new line. The file can contain any number of records. this how .dat file looks when opened using a notepad editor
Your code "works" on my system.
The following compiles (without "using namespace std;")
I changed the file name for my convenience.
I created the 't391.dat' file in the same working directory of the code, and put in 10 lines, with 1 value per line, 1..9,0.
#include <fstream>
#include <iostream>
int t391a(void)
{
std::ifstream file;
file.open("t391.dat");
int data=0;
file >> data;
std::cout << data << std::endl; // echo of input / proof it works
//system("pause");
file.close();
return 0;
}
This code outputs the first value (which is all it attempts to do), so it is working!
The echo of input is good idea.
As an experiment, I temporarily renamed the 't391.dat' file to something else. The code ran to completion and printed a single 0, which is not the first value in the file. Perhaps this suggests your file is not being found, I won't guess. To confirm, I restored the file, and the above 'works' again.
Missing items in your code:
error check - file.open()
a loop to read to end of file
error check - formatted extract (i.e. read from stream) of data item
file.close - possibly not needed
If you are still working this issue, I have a minimally extended version of your code that addresses these issues. Let me know.
class ValueGet {
public:
int data;
ValueGet() {
data = 0;
}
};
int main()
{
ValueGet vg;
ifstream file;
file.open("data1.dat", fstream::binary | fstream::out); // Opens a file in binary mode for input operations i.e., getting data from file.
if (!file)
cout << "File Not Found." << endl;
else {
file.seekg(0); // To make sure that the data is read from the starting position of the file.
while (file.read((char *)&vg, sizeof(vg))) // Iterates through the file till the pointer reads the last line of the file.
cout<<vg.data<<endl;
}
//system("pause");
return 0;
}
output of the data in the file
Here is one way which I just found
#include <bits/stdc++.h>
using namespace std;
int main(){
unsigned int a;
unsigned char c;
ifstream file;
file.open("ou.bin", ios::binary);
if(!file.is_open()){
cout<<"error";
return 0;
}
for(int i=0; i<8; i++){
file>>c;
a = c;
a = a<<8;
file>>c;
a = a+ c;
cout<<a<<endl;
}
file.close();
return 0;
}
This for storing two bytes in a number you can store as many bytes in a number or even one.
Hope this helps.
You will not be able to read .dat files and understand them in your context-- they are general formats used for storing data. Unless you know the contents of it or how they are specified, you will always get junk.
I'am having a rather difficult time with this program (see code below). It is supposed to :
Create an array of 26 components to do the letter count for the 26 letters in the alphabet and a variable for the line count.
Create an ASCII (or text) file that contains text and will be used as input to my program.
Call that file "textinput" and then, have the output stored in a file called "textoutput".
Can anyone tell me what I'am doing wrong? I keep getting "File not found" errors.
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <cstdlib>
#include <fstream>
using namespace std;
int main()
{
int lineCount = 0;
int letterCount[26];
for(int i = 0; i < 26; i++)
letterCount[i] = 0;
ifstream infile;
infile.open("textinput.txt", ios::in);
if(!infile)
{
cerr<<"File does not exist."<<endl;
exit(1);
}
ofstream outfile;
outfile.open("textoutput.txt", ios::out|ios::binary);
if(!outfile)
{
cerr<<"File cannot be opened."<<endl;
exit(1);
}
char data[100];
outfile<<data;
while(infile>>data)
{
outfile<<data<<endl;
}
while(infile)
{
char ch1 = infile.get();
if(ch1 == '\n')
{
lineCount++;
continue;
}
int asciiNum = (int)ch1;
if(asciiNum > 96)
{
asciiNum = asciiNum - 97;
}
else
{
asciiNum = asciiNum - 65;
}
letterCount[asciiNum]++;
}
infile.close();
outfile.close();
system("PAUSE");
return 0;
}
The funny thing is, "File not found" errors are not possible with your program.1 So, I'm going out on a limb and suggest that you need to qualify the path to your executable!
Say, you compiled with something like
gcc program1.cpp -o program1
To execute, you must use
./program1
Because program1 won't work. The reason is that with 99% certainty, your current working directory is not in the search PATH for executables (and you want to keep it that way).
Beyond this, yes, do make sure that the textinput.txt exists in the same directory.
1(There's no such error message in the program. You should know: you programmed it!)
ifstream class is used to read from files and to read from files you must need to create it first which you haven't done, so first create the file .
By doing like this :
ifstream infile;
infile.open("textinput.txt", ios::in);
you are trying to read from a file which has not been created yet OR may be as described in other answer or the comments that your file doesn't exist in the same directory.
You better use ofstream to first write on the file and then use ifstream.
Does your code work if you have the file? If it does try removing the ios::out.If i'm not mistaken ios::out is used when you do not want to truncate your old content in the file,but that implies you already have it.
I need to read a jpg file to a string. I want to upload this file to our server, I just find out that the API requires a string as the data of this pic. I followed the suggestions in a former question I've asked Upload pics to a server using c++ .
int main() {
ifstream fin("cloud.jpg");
ofstream fout("test.jpg");//for testing purpose, to see if the string is a right copy
ostringstream ostrm;
unsigned char tmp;
int count = 0;
while ( fin >> tmp ) {
++count;//for testing purpose
ostrm << tmp;
}
string data( ostrm.str() );
cout << count << endl;//ouput 60! Definitely not the right size
fout << string;//only 60 bytes
return 0;
}
Why it stops at 60? It's a strange character at 60, and what should I do to read the jpg to a string?
UPDATE
Almost there, but after using the suggested method, when I rewrite the string to the output file, it distorted. Find out that I should also specify that the ofstream is in binary mode by ofstream::binary. Done!
By the way what's the difference between ifstream::binary & ios::binary, is there any abbreviation for ofstream::binary?
Open the file in binary mode, otherwise it will have funny behavior, and it will handle certain non-text characters in inappropriate ways, at least on Windows.
ifstream fin("cloud.jpg", ios::binary);
Also, instead of a while loop, you can just read the whole file in one shot:
ostrm << fin.rdbuf();
You shouldn't read the file to a string because it is legal for a jpg to contain values that are 0. However in a string, the value 0 has a special meaning (it's the end of string indicator aka \0). You should instead read the file into a vector. You can do this easily like so:
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
int main(int argc, char* argv[])
{
std::ifstream ifs("C:\\Users\\Borgleader\\Documents\\Rapptz.h");
if(!ifs)
{
return -1;
}
std::vector<char> data = std::vector<char>(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
//If you really need it in a string you can initialize it the same way as the vector
std::string data2 = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
std::for_each(data.begin(), data.end(), [](char c) { std::cout << c; });
std::cin.get();
return 0;
}
Try opening the file in binary mode:
ifstream fin("cloud.jpg", std::ios::binary);
At a guess, you were probably trying to read the file on Windows and the 61st character was probably 0x26 -- a control-Z, which (on Windows) will be treated as marking the end of the file.
As far as how to best do the reading, you end up with a choice between simplicity and speed, as demonstrated in a previous answer.