I have to handle with code where at one side information is written to a file using FILE* and on the other side it is read-in using ifstream.
I tried to compile a dummy code which shows the same behavior as the original code:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
int main()
{
FILE* outFile = fopen("testFile", "w");
char* posBuf = NULL;
unsigned int counter = 0;
posBuf = (char*) malloc( sizeof(int) + 2*sizeof(double) );
int iDummy = 123;
memcpy(posBuf+counter, (const void*) &iDummy, sizeof(int));
counter += sizeof(int);
double dDummy = 456.78;
memcpy(posBuf+counter, (const void*) &dDummy, sizeof(double));
counter += sizeof(double);
dDummy = 111.222;
memcpy(posBuf+counter, (const void*) &dDummy, sizeof(double));
fputs(posBuf, outFile);
fclose(outFile);
/////////////////////
std::ifstream myfile;
myfile.open("testFile", std::ios::in|std::ios::binary);
myfile.seekg (0, std::ios::end);
unsigned int length = myfile.tellg();
myfile.seekg (0, std::ios::beg);
char* posBuf2 = (char*) malloc( length );
myfile.read(posBuf2, length);
counter = 0;
int idummy = 0;
memcpy((void*) &idummy, posBuf2+counter, sizeof(int));
counter += sizeof(int);
printf("read integer: %u\n", idummy);
double ddummy = 1.0;
memcpy((void*) &ddummy, posBuf2+counter, sizeof(double));
counter += sizeof(double);
printf("read double: %f\n", ddummy);
ddummy = 1.0;
memcpy((void*) &ddummy, posBuf2+counter, sizeof(double));
counter += sizeof(double);
printf("read double: %f\n", ddummy);
myfile.close();
/////////////////////
FILE* inFile = fopen("testFile", "r");
char* posBuf3 = NULL;
unsigned int c = 0;
while ( ! feof (inFile) )
{
posBuf3 = (char*) realloc((void*) posBuf3, c+4);
fgets(posBuf3+c, 4, inFile);
c += 4;
}
idummy = 0;
memcpy((void*) &idummy, posBuf, sizeof(int));
printf("read again integer: %u\n", idummy);
ddummy =1.0;
memcpy((void*) &ddummy, posBuf+sizeof(int), sizeof(double));
printf("read again double: %f\n", ddummy);
ddummy =1.0;
memcpy((void*) &ddummy, posBuf+sizeof(int)+sizeof(double), sizeof(double));
printf("read again double: %f\n", ddummy);
return 0;
}
The output I get from that is:
read integer: 123
read double: 0.000000
read double: 0.000000
read again integer: 123
read again double: 456.780000
read again double: 111.222000
As you can see, the deserialization only works if I use FILE* also for the reading of the file.
QUESTION: Any explanation for that behavior?
Thanks!
UPDATED:
1) open ifstream using std::ios::in|std::ios::binary
2) fix malloc
A few problems with the posted code:
it is writing beyond the bounds of the memory allocated for posBuf (1 int and 2 doubles are copied to the memory, but only sizeof(int) + sizeof(double) is allocated), which is undefined behaviour.
fputs() treats its argument as a null terminated string and so will stop writing when it encounters a null character. Open the file in binary mode and use fwrite() instead which does not treat its input as a null terminated string.
There are several other issues with the code;
it is a horrible mix of C and C++
avoidable explicit dynamic memory management (never mind malloc() and realloc()). Simply replaced with:
char posBuf[sizeof(int) + 2 * sizeof(double)];
while (!feof(inFile)).
there is practically no checking of the success of I/O operations
Related
I have a homework about WAV files and FIR filters for a Digital Signal Processing class.
My program must read a WAV file, apply a filter to the data and write the output data to another WAV file again.
I have completed reading and applying filters but I can't write the WAV file. The program doesn't give any errors while compiling but the WAV file doesn't play.
If I write "temp" to the WAV, it runs properly. But if I write "data", it doesn't.
How can I write a WAV file properly?
#define _CRT_SECURE_NO_WARNINGS
#define PI 3.14f
#define WAV_HEADER_LENGTH 44
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>
char* read_wav(const char* filename, short*, short*, int*);
void write_wav(const char* filename, const char*, int);
using namespace std;
int main()
{
short nchannel, ssample;
int csample;
//Reading WAV file and returning the data.
char* temp = read_wav("sum.wav", &nchannel, &ssample, &csample);
short* data = (short*)&temp[WAV_HEADER_LENGTH];
cout << "How many coefficients are there in filter ?" << endl;
int N;
cin >> N ;
float filter[N];
cout << "Type coefficients in filter." << endl;
for(int i=0; i<N;i++){
cin >> filter[i];
}
short* output = (short*)&temp[WAV_HEADER_LENGTH];
for(int i=0; i < csample; i++){
double sum = 0;
for(int j=0; j < N; j++){
if((i - j) >= 0)
sum += filter[j] * data[i-j];
}
output[i] = (short) sum;
}
write_wav("test.wav", out, csample * ssample + WAV_HEADER_LENGTH);
}
char* read_wav(const char* filename, short* nchannel, short* ssample, int* csample) {
//Reading the file.
FILE* fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Couldn't open the file \"%s\"\n", filename);
exit(0);
}
fseek(fp, 0, SEEK_END);
int file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("The file \"%s\" has %d bytes\n\n", filename, file_size);
char* buffer = (char*)malloc(sizeof(char) * file_size);
fread(buffer, file_size, 1, fp);
// Dump the buffer info.
*nchannel = *(short*)&buffer[22];
*ssample = *(short*)&buffer[34] / 8;
*csample = *(int*)&buffer[40] / *ssample;
printf("ChunkSize :\t %u\n", *(int*)&buffer[4]);
printf("Format :\t %u\n", *(short*)&buffer[20]);
printf("NumChannels :\t %u\n", *(short*)&buffer[22]);
printf("SampleRate :\t %u\n", *(int*)&buffer[24]); // number of samples per second
printf("ByteRate :\t %u\n", *(int*)&buffer[28]); // number of bytes per second
printf("BitsPerSample :\t %u\n", *(short*)&buffer[34]);
printf("Subchunk2ID :\t \"%c%c%c%c\"\n", buffer[36], buffer[37], buffer[38], buffer[39]); // marks beginning of the data section
printf("Subchunk2Size :\t %u\n", *(int*)&buffer[40]); // size of data (byte)
printf("Duration :\t %fs\n\n", (float)(*(int*)&buffer[40]) / *(int*)&buffer[28]);
fclose(fp);
return buffer;
}
void write_wav(const char* filename, const char* data, int len) {
FILE* fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Couldn't open the file \"%s\"\n", filename);
exit(0);
}
fwrite(data, len, 1, fp);
fclose(fp);
}
This works for me:
int main()
{
short nchannel, ssample;
int csample;
// Reading WAV file and returning the data.
char* temp = read_wav("sum.wav", &nchannel, &ssample, &csample);
short* data = (short*)&temp[WAV_HEADER_LENGTH];
// cout << "How many coefficients are there in filter ?" << endl;
const int N = 2;
// cin >> N;
float filter[N] = {0.5, 0.75};
// cout << "Type coefficients in filter." << endl;
// for (int i = 0; i < N; i++)
// {
// cin >> filter[i];
// }
short* output = (short*)&temp[WAV_HEADER_LENGTH];
for (int i = 0; i < csample; i++)
{
double sum = 0;
for (int j = 0; j < N; j++)
{
if ((i - j) >= 0) sum += filter[j] * data[i - j];
}
output[i] = (short)sum;
}
write_wav("test.wav", (char*)temp, csample * ssample + WAV_HEADER_LENGTH);
}
My changes:
The major change is to use the full buffer, with extremely misleading name: temp, instead of your out that does not compile, as the argument of write_wav.
I applied "my" filter coefficients (the sound from the output file is really distorted),
I applied my favorite indentation
If the code is to be portable, you need to check the endiannes and act accordingly.
I would expect the input and output files to be of the same length, but they're not. Please check it yourself why this is not the case.
Example:
-rw-r--r-- 1 zkoza zkoza 787306 06-23 14:09 sum.wav
-rw-r--r-- 1 zkoza zkoza 787176 06-23 14:16 test.wav
It looks like 130 bytes are missing in the output file.
Your float filter[N] with N not known at compile time is a C++ extension: please use std::vector in your final code instead.
Next time please provide also a link for any input files. For my tests, I used https://freewavesamples.com/alesis-fusion-clean-guitar-c3 , but all these little things, like finding an input file (WAV format has several flavors, I could have missed the correct one), guessing filter parameters etc. take time and effort.
Your condition if ((i - j) >= 0) can be written in a way easier to understand; preferably by changing the inner loop "header".
I am trying to assign a value to a specific index in a vector. I am getting a segmentation fault when attempting to do so. Here is my code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int sp = -1; // Stack pointer
int pc = 0; // Program counter
int fpsp = -1; // Frame pointer stack pointer
vector<int> rstack; // Runtime Stack
vector<int> fpstack; // Frame Pointer Stack
int getInt(unsigned char a, unsigned char b, unsigned char c, unsigned char d) {
int i = (d << 24) | (c << 16) | (b << 8) | a;
return i;
}
int main(void) {
// Reading size of file
FILE * file = fopen("Samples/Ground_Truth/interpreter_input.smp", "r+");
fseek(file, 0, SEEK_END);
long int size = ftell(file);
fclose(file);
// Reading data to memory array
file = fopen("Samples/Ground_Truth/interpreter_input.smp", "r+");
unsigned char * mem = (unsigned char *) malloc(size);
int bytes_read = fread(mem, sizeof(unsigned char), size, file);
fclose(file);
bool halt = 0;
while(!halt) {
int i = getInt(mem[pc + 1], mem[pc + 2], mem[pc + 3], mem[pc + 4]);
rstack[++sp] = i;
pc += 5;
halt = 1;
}
}
When trying to perform rstack[++sp] = i; I receive a seg fault. However, if I use rstack.push_back(i) it works fine. However, I would like to be able to directly assign this value by referencing the index.
I read a binary file of raw PCM data but cannot convert it to floats correctly. I am reading a raw pcm file that audacity recognizes as 16 bit unsigned. I am using the following code:
fseek(stream, 0, SEEK_END);
size = ftell(stream);
fseek(stream, 0, SEEK_SET);
uint8_t * buf = (uint8_t *)malloc(size);
float * f = (float *)malloc(size * sizeof(float) / 2);
//read buffer
fread(buf, sizeof(uint8_t), size, stream);
//convert to float:
for(int j=0;j<size;j+=2){
int16_t temp1 = buf[j] | buf[j+1] << 8;
f[j/2]=(float)temp1/(float)32767.0;
if( f[j/2] > 1 )
f[j/2] = 1;
if( f[j/2] < -1 )
f[j/2] = -1;
}
What am I doing wrong here?
j increments by 2 so you are only filling in every other value of f[].
Instead, assign f[j>>1]
Hopefully you allocated f to hold at least j/2 floats.
I have a binary data file that contains 2d and 3d coordinates in such order:
uint32 numberOfUVvectors;
2Dvec uv[numberOfUVvectors];
uint32 numberOfPositionVectors;
3Dvec position[numberOfPositionVectors];
uint32 numberOfNormalVectors;
3Dvec normal[numberOfNormalVectors];
2Dvec and 3Dvec are structs composed from 2 and 3 floats respectively.
At first, I read all these values using the "usual" way:
in.read(reinterpret_cast<char *>(&num2d), sizeof(uint32));
2Dvectors.reserve(num2d); // It's for an std::vector<2DVec> 2Dvectors();
for (int i = 0; i < num2d; i++){
2Dvec 2Dvector;
in.read(reinterpret_cast<char *>(&2Dvector), sizeof(2DVec));
2Dvectors.push_back(2Dvector);
}
It worked fine, but it was painfully slow (there can be more than 200k entries in a file and with so many read calls, the hdd access became a bottleneck). I decided to read the entire file into a buffer at once:
in.seekg (0, in.end);
int length = in.tellg();
in.seekg (0, in.beg);
char * buffer = new char [length];
is.read (buffer,length);
The reading is way faster now, but here's the question: how to parse that char buffer back into integers and structs?
To answer your specific question:
unsigned char * pbuffer = (unsigned char *)buffer;
uint32 num2d = *((uint32 *)pbuffer);
pbuffer += sizeof(uint32);
if(num2d)
{
2Dvec * p2Dvec = (2Dvec *)pbuffer;
2Dvectors.assign(p2Dvec, p2Dvec + num2d);
pbuffer += (num2d * sizeof(2Dvec));
}
uint32 numpos = *((uint32 *)pbuffer);
pbuffer += sizeof(uint32);
if(numpos)
{
3Dvec * p3Dvec = (3Dvec *)pbuffer;
Pos3Dvectors.assign(p3Dvec, p3Dvec + numpos);
pbuffer += (numpos * sizeof(3Dvec));
}
uint32 numnorm = *((uint32 *)pbuffer);
pbuffer += sizeof(uint32);
if(numnorm)
{
3Dvec * p3Dvec = (3Dvec *)pbuffer;
Normal3Dvectors.assign(p3Dvec, p3Dvec + numnorm);
pbuffer += (numnorm * sizeof(3Dvec));
}
// do not forget to release the allocated buffer
A an even faster way would be:
in.read(reinterpret_cast<char *>(&num2d), sizeof(uint32));
if(num2d)
{
2Dvectors.resize(num2d);
2Dvec * p2Dvec = &2Dvectors[0];
in.read(reinterpret_cast<char *>(&p2Dvec), num2d * sizeof(2Dvec));
}
//repeat for position & normal vectors
Use memcpy with the appropriate sizes and start values
or cast the values (example):
#include <iostream>
void copy_array(void *a, void const *b, std::size_t size, int amount)
{
std::size_t bytes = size * amount;
for (int i = 0; i < bytes; ++i)
reinterpret_cast<char *>(a)[i] = static_cast<char const *>(b)[i];
}
int main()
{
int a[10], b[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
copy_array(a, b, sizeof(b[0]), 10);
for (int i = 0; i < 10; ++i)
std::cout << a[i] << ' ';
}
I am trying to read a large file (~5GB) using ifstream in C++.
Since I'm on a 64bit OS, I thought this shouldn't be a problem.
Still, I get a segfault. Everything runs fine with smaller files,
so I'm pretty sure that is where the problem is.
I'm using g++ (4.4.5-8) and libstdc++6 (4.4.5-8).
Thanks.
The code looks like this:
void load (const std::string &path, int _dim, int skip = 0, int gap = 0) {
std::ifstream is(path.c_str(), std::ios::binary);
BOOST_VERIFY(is);
is.seekg(0, std::ios::end);
size_t size = is.tellg();
size -= skip;
long int line = sizeof(float) * _dim + gap;
BOOST_VERIFY(size % line == 0);
long int _N = size / line;
reset(_dim, _N);
is.seekg(skip, std::ios::beg);
char *off = dims;
for (long int i = 0; i < N; ++i) {
is.read(off, sizeof(T) * dim);
is.seekg(gap, std::ios::cur);
off += stride;
}
BOOST_VERIFY(is);
}
The segfault is in the is.read line for i=187664.
T is float and I'm reading dim=1000 floats at a time.
When the segfault occures, i * stride is way smaller than size, so I'm not running past the end of the file.
dims is allocated here
void reset (int _dim, int _N)
{
BOOST_ASSERT((ALIGN % sizeof(T)) == 0);
dim = _dim;
N = _N;
stride = dim * sizeof(T) + ALIGN - 1;
stride = stride / ALIGN * ALIGN;
if (dims != NULL) delete[] dims;
dims = (char *)memalign(ALIGN, N * stride);
std::fill(dims, dims + N * stride, 0);
}
I don't know if this is the bug, but this code looks very C like and plenty of opportunity to leak. Any way try changing
void reset (int _dim, int _N)
to
void reset (size_t dim, size_t _N)
//I would avoid using leading underscores that is usually used to identify elements of the standard library.
When you are dealing with the size or index of something in memory ALWAYS use size_t, it is guaranteed to be able to hold the maximum size of an object including arrays.
I think you have to use _ftelli64 etc... to have the right size of your file, and to use long long (or _int64) variables to manage it. But it's C library. I don't find how to use ifstream with so big file (actualy > 2Go). Did you find the way ?
PS : In your case size_t is fine, but I'm not sure that's OK with 32-bit software. I'm sure it's OK with 64-bit.
int main()
{
string name="tstFile.bin";
FILE *inFile,*inFile2;
fopen_s(&inFile,name.c_str(),"rb");
if (!inFile)
{
cout<<"\r\n***error -> File not found\r\n";
return 0;
}
_fseeki64 (inFile,0L,SEEK_END);
long long fileLength = _ftelli64(inFile);
_fseeki64 (inFile,0L,SEEK_SET);
cout<<"file lg : "<<fileLength<<endl;
return 1;
}