I'm having a problem working on a Random Access File class in c++, which should allow to write & read any primitive datatype from a file. However, even though the code compiles and executes, nothing is written to the file.
File is openend in constructor:
RandomAccessFile::RandomAccessFile(const string& fileName) : m_fileName(fileName) {
// try to open file for reading and writing
m_file.open(fileName.c_str(), ios::in|ios::out|ios::binary);
if (!m_file) {
// file doesn't exist
m_file.clear();
// create new file
m_file.open(fileName.c_str(), ios::out | ios::binary);
m_file.close();
// try to open file for reading and writing
m_file.open(fileName.c_str(), ios::in|ios::out|ios::binary);
if (!m_file) {
m_file.setf(ios::failbit);
}
}
}
Test call of function in main:
RandomAccessFile raf("C:\Temp\Vec.txt");
char c = 'c';
raf.write(c);
Write function:
template<class T>
void RandomAccessFile::write(const T& data, streampos pos) {
if (m_file.fail()) {
throw new IOException("Could not open file");
}
if (pos > 0) {
m_file.seekp(pos);
}
else {
m_file.seekp(0);
}
streamsize dataTypeSize = sizeof(T);
char *buffer = new char[dataTypeSize];
for (int i = 0; i < dataTypeSize; i++) {
buffer[dataTypeSize - 1 - i] = (data >> (i * 8));
}
m_file.write(buffer, dataTypeSize);
delete[] buffer;
}
If I debug it I can cleary see that 'c' is in the buffer when it's written to the file.
Any suggestions?
Thanks
Phil
Solved it myself with a little luck.
Apparently, fstream.open doesn't work with absolute paths.
Replacing "C.\temp\vec.txt" with just "temp" solved it.
Related
Hey I've a dynamic array and I want to load to this array the data of my Wav file, I already wrote the beginning but I can't figure it out how to load the file in my dynamic array, can somebody help me further with this code?
#include <iostream>
using namespace std;
template <typename T>
class Array{
public:
int size;
T *arr;
Array(int s){
size = s;
arr = new T[size];
}
T& operator[](int index)
{
if (index > size)
resize(index);
return arr[index];
}
void resize(int newSize) {
T* newArray = new T[newSize];
for (int i = 0; i <size; i++)
{
newArrayi] = arr[i];
}
delete[] arr;
arr = newArray;
size = newSize;
}
};
int main(){
Array<char> wavArray(10);
FILE *inputFile;
inputFile =fopen("song.wav", "rb");
return 0;
}
if you just want to load the complete file into memory, this may come in handy:
#include <iterator>
// a function to load everything from an istream into a std::vector<char>
std::vector<char> load_from_stream(std::istream& is) {
return {std::istreambuf_iterator<char>(is), std::istreambuf_iterator<char>()};
}
... and use the C++ file streaming classes to open and automatically close files.
{
// open the file
std::ifstream is(file, std::ios::binary);
// check if it's opened
if(is) {
// call the function to load all from the stream
auto content = load_from_stream(is);
// print what we got (works on textfiles)
std::copy(content.begin(), content.end(),
std::ostream_iterator<char>(std::cout));
} else {
std::cerr << "failed opening " << file << "\n";
}
}
... but a WAV file contains a lot of different chunks describing the contents of the file so you may want to create individual classes for streaming these chunks to and from files.
char* readFileBytes(const char *name)
{
FILE *fl = fopen(name, "r");
fseek(fl, 0, SEEK_END);
long len = ftell(fl);
char *ret = malloc(len);
fseek(fl, 0, SEEK_SET);
fread(ret, 1, len, fl);
fclose(fl);
return ret;
}
I am confused as to where in my code am I getting it wrong. Instead of resulting to 1,2,3 the output is 1,1,1. Any suggestions as to what I can do? I am guessing my error lies either in the writing data or when I use the variable value.
class Binary
{
public:
Binary(int num);
~Binary();
void createBinary();
void writeBinary();
void readBinary();
string binFile;
int value;
fstream binaryFile;
};
Binary::Binary(int num)
{
value = num;
binFile = "BinaryFile.bin";
}
Binary::~Binary()
{
}
void Binary::createBinary()
{
binaryFile.open(binFile, ios::out | ios::binary);
binaryFile.close();
}
void Binary::writeBinary()
{
if (!binaryFile) //if file does not exist
{
createBinary();
}
binaryFile.open(binFile, ios::app | ios::binary);
binaryFile.write((char*)&value, sizeof(value));
binaryFile.close();
}
void Binary::readBinary()
{
binaryFile.open(binFile, ios::in |ios::binary);
binaryFile.read((char*)&value, sizeof(value));
binaryFile.close();
cout << value << ", ";
}
int main()
{
Binary num1(1);
Binary num2(2);
Binary num3(3);
num1.writeBinary();
num2.writeBinary();
num3.writeBinary();
num1.readBinary();
num2.readBinary();
num3.readBinary();
return 0;
}
Since you use a single file and read from start at each Binary()::readBinary(), your result is as expected. Either use different files for each of your objects.
// In general we may need some random part in name but for this special case,
// since you are just writing / reading value, the following seems to work.
Binary::Binary(int num)
{
value = num;
binFile = "BinaryFile"; // common start
binFile += std::to_string(value); // differentiator
binFile += ".bin"; // extension
}
Or, if you want to use the same file, try to get help from a static variable for not to read the same line again and again.
I'm trying to read an array object (Array is a class I've made using read and write functions to read and write from binary files. So far the write functions works but it won't read from the file properly for some reason. This is the write function :
void writeToBinFile(const char* path) const
{
ofstream ofs(path, ios_base::out | ios_base::app | ios_base::binary);
if (ofs.is_open())
{
ostringstream oss;
for (unsigned int i = 0; i < m_size; i++)
{
oss << ' ';
oss << m_data[i];
}
ofs.write(oss.str().c_str(), oss.str().size());
}
}
This is the read function :
void readFromBinFile(const char* path)
{
ifstream ifs(path, ios_base::in | ios_base::binary || ios_base::ate);
if (ifs.is_open())
{
stringstream ss;
int charCount = 0, spaceCount = 0;
ifs.unget();
while (spaceCount != m_size)
{
charCount++;
if (ifs.peek() == ' ')
{
spaceCount++;
}
ifs.unget();
}
ifs.get();
char* ch = new char[sizeof(char) * charCount];
ifs.read(ch, sizeof(char) * charCount);
ss << ch;
delete[] ch;
for (unsigned int i = 0; i < m_size; i++)
{
ss >> m_data[i];
m_elementCount++;
}
}
}
those are the class fields :
T* m_data;
unsigned int m_size;
unsigned int m_elementCount;
I'm using the following code to write and then read (1 execution for reading another for writing):
Array<int> arr3(5);
//arr3[0] = 38;
//arr3[1] = 22;
//arr3[2] = 55;
//arr3[3] = 7;
//arr3[4] = 94;
//arr3.writeToBinFile("binfile.bin");
arr3.readFromBinFile("binfile.bin");
for (unsigned int i = 0; i < arr3.elementCount(); i++)
{
cout << "arr3[" << i << "] = " << arr3[i] << endl;
}
The problem is now at the readFromBinFile function, it get stuck in an infinite loop and peek() returns -1 for some reason and I can't figure why.
Also note I'm writing to the binary file using spaces to make a barrier between each element so I would know to differentiate between objects in the array and also a space at the start of the writing to make a barrier between previous stored binary data in the file to the array binary data.
The major problem, in my mind, is that you write fixed-size binary data in variable-size textual form. It could be so much simpler if you just stick to pure binary form.
Instead of writing to a string stream and then writing that output to the actual file, just write the binary data directly to the file:
ofs.write(reinterpret_cast<char*>(m_data), sizeof(m_data[0]) * m_size);
Then do something similar when reading the data.
For this to work, you of course need to save the number of entries in the array/vector first before writing the actual data.
So the actual write function could be as simple as
void writeToBinFile(const char* path) const
{
ofstream ofs(path, ios_base::out | ios_base::binary);
if (ofs)
{
ofs.write(reinterpret_cast<const char*>(&m_size), sizeof(m_size));
ofs.write(reinterpret_cast<const char*>(&m_data[0]), sizeof(m_data[0]) * m_size);
}
}
And the read function
void readFromBinFile(const char* path)
{
ifstream ifs(path, ios_base::in | ios_base::binary);
if (ifs)
{
// Read the size
ifs.read(reinterpret_cast<char*>(&m_size), sizeof(m_size));
// Read all the data
ifs.read(reinterpret_cast<char*>(&m_data[0]), sizeof(m_data[0]) * m_size);
}
}
Depending on how you define m_data you might need to allocate memory for it before reading the actual data.
Oh, and if you want to append data at the end of the array (but why would you, in the current code you show, you rewrite the whole array anyway) you write the size at the beginning, seek to the end, and then write the new data.
I'm new to c++ coding. I'm trying to write a function that opens specified ".txt" files(I fed up with coping/pasting multiple times).What I need to realize:
Specify filename;
read data and save to double(type) array;
return array;
As far as I understood, c++ can't return array, but it can return pointer. The problem is: how to use it? Any help will be appreciated. :)
P.S My draft code (it's working):
double arr[10];
fstream file;
file.open("input.txt");
if(file.is_open()){
while(file.good()){
for(int i = 0 ; i < 10 ; i++){
file >> arr[i];
}
}
file.close();
}else{
cout<<"[ERROR]: File \"input.txt\" wasn't found!"<<endl;
cout<<"[INFO]: Terminating program...";
Sleep(1000);
exit(0);
}
I dunno how to write as a function. Moreover I dunno how to use it
To start, try this:
std::vector<double> theFunction(const std::string &filename)
{
std::vector<double> arr(10);
std::fstream file(filename);
if (file)
{
for (int i = 0 ; i < 10 && file.good(); i++)
file >> arr[i];
}
return arr;
}
std::vector<double> result = theFunction("input.txt");
if (result.empty())
// Can not read the file
I'm having some trouble with replacing a portion of a file in binary mode. For some reason my seekp() line is not placing the file pointer at the desired position. Right now its appending the new contents to the end of the file instead of replacing the desired portion.
long int pos;
bool found = false;
fstream file(fileName, ios::binary|ios::out|ios::in);
file.read(reinterpret_cast<char *>(&record), sizeof(Person));
while (!file.eof())
{
if (record.getNumber() == number) {
pos=file.tellg();
found = true;
break;
}
// the record object is updated here
file.seekp(pos, ios::beg); //this is not placing the file pointer at the desired place
file.write(reinterpret_cast<const char *>(&record), sizeof(Person));
cout << "Record updated." << endl;
file.close();
Am I doing something wrong?
Thanks a lot in advance.
I don't see how your while() loop can work. In general, you should not test for eof() but instead test if a read operation worked.
The following code writes a record to a file (which must exist) and then overwrites it:
#include <iostream>
#include <fstream>
using namespace std;
struct P {
int n;
};
int main() {
fstream file( "afile.dat" , ios::binary|ios::out|ios::in);
P p;
p.n = 1;
file.write( (char*)&p, sizeof(p) );
p.n = 2;
int pos = 0;
file.seekp(pos, ios::beg);
file.write( (char*)&p, sizeof(p) );
}
while (!file.eof())
{
if (record.getNumber() == number) {
pos=file.tellg();
found = true;
break;
}
here -- you`re not updating number nor record -- so basically you go through all file and write in "some" location (pos isn't inited)
And Neil Butterworth is right (posted while i typed 8)) seems like you omitted smth