I desperately try to write in a ostringstream and then transfert the datas in the istringstream of an other object or in a file.
std::ostringstream oss;
oss << "Hello World";
For the first purpose, I try this :
iss.basic_ios<char>::rdbuf(oss.rdbuf());
But a simple "iss.str()" return nothing at all. (First problem)
Then when I try that :
std::ofstream ofs("test.txt");
ofs << oss.rdbuf();
ofs.close();
Nothing is written in the file test.txt. (Second problem)
Thank you in advance for any explanation of the inside relation between stringstream and streambuf.
You're under a misapprehension - doing iss.basic_ios<char>::rdbuf(oss.rdbuf()) only changes the internal pointer of the input string stream to point to the other output string stream's buffer. It has no affect on the content of the internal buffer of iss (i.e there is no transfer of data).
As far as I know the get area of an input string stream can be invalid and unused entirely by its implementation. I don't think there's any way to change that.
Related
I'm writing 8-bit PIC microcontroller C code in Microchip's MPLAB X tool using their XC8 compiler for a demo / evaluation board for a sensor IC. The PIC I'm using has multiple serial ports, so I'm using UART2 to output only sensor data. I wanted to be able to format the output data for hex or decimal so I have stdio redirected to this port. The Rx side of UART2 is unused.
UART1 is used for command and control. This port needs to be able to output ASCII messages such as "Enter the register address:". The sensor is highly configurable, so my code initializes it with default values, but the user can halt sampling, read and write registers and re-start sampling.
Since I can't use printf when writing to UART1, I had to find another way to do this. Here's an example of what I'm doing. The file is large so I'm just cutting and pasting the relevent stuff here:
char msgString[64];
switch(command)
{
case (READCMD): // Read command
{
if (SERIAL_STATE_IDLE == serialPortState)
{
strcpy (msgString, "Input Read Address Hex Value 00-18");
Display_PrintMessage();
Display_PrintChar(prompt);
serialPortState = SERIAL_STATE_READ;
}
...
void Display_PrintMessage(void)
{
msgLength=strlen(msgString);
for (i=0; i<msgLength; ++i)
{
UART1_Write(msgString[i]);
}
Display_PrintChar(newLine);
}
void Display_PrintChar(char c)
{
UART1_Write(c);
}
I've verified that the port is working by writing some characters out to it early in main and they do appear on my terminal. I think the problem is with how I'm using the strcpy function. In the MPLAB debugger it appears that msgString is still all null characters after the strcpy executes. The strlen function may see msgString as zero length, hence, nothing prints out.
I would love to hear what you think may be wrong with my code, or, please suggest another way of accomplishing what I need.
Thanks in advance for any and all responses, they are much appreciated.
CobraRGuy
I tried to write String in DataInputStream, when read from DataInputStream single char, but I have an error.
I expected, that readChar() return 'q', but method:
assertEquals('q', DataInputStream("q".byteInputStream(Charsets.UTF_8)).readChar())
Throws exception:
java.io.EOFException
at java.io.DataInputStream.readChar(DataInputStream.java:365)
Please have a look at DataInput.readChar() which states:
Reads two input bytes and returns a char value. Let a be the first byte read and b be the second byte. The value returned is:
(char)((a << 8) | (b & 0xff))
This method is suitable for reading bytes written by the writeChar method of interface DataOutput.
The last sentence is basically also the solution. If you write the data using writeChar, reading works as expected, i.e. the following will give you a succeeding test case:
assertEquals('q', DataInputStream(ByteArrayOutputStream().apply {
DataOutputStream(this).use {
it.writeChars("q")
}
}.toByteArray().inputStream())
.readChar())
The following, even though not mentioned in the interface, may also work out:
assertEquals('q', DataInputStream("q".byteInputStream(Charsets.UTF_16BE)).readChar())
I have an array of objects that each needs to load itself from binary file data. I create an array of these objects and then call an AsyncAction for each of them that starts it reading in its data. Trouble is, they are not loading entirely - they tend to get only part of the data from the files. How can I make sure that the whole thing is read? Here is an outline of the code: first I enumerate the folder contents to get a StorageFile for each file it contains. Then, in a for loop, each receiving object is created and passed the next StorageFile, and it creates its own Buffer and DataReader to handle the read. m_file_bytes is a std::vector.
m_buffer = co_await FileIO::ReadBufferAsync(nextFile);
m_data_reader = winrt::Windows::Storage::Streams::DataReader::FromBuffer(m_buffer);
m_file_bytes.resize(m_buffer.Length());
m_data_reader.ReadBytes(m_file_bytes);
My thought was that since the buffer and reader are class members of the object they would not go out of scope and could finish their work uninterrupted as the next objects were asked to load themselves in separate AsyncActions. But the DataReader only gets maybe half of the file data or less. What can be done to make sure it completes? Thanks for any insights.
[Update] Perhaps what is going is that the file system can handle only one read task at a time, and by starting all these async reads each is interrupting the previous one -? But there must be a way to progressively read a folder full of files.
[Update] I think I have it working, by adopting the principle of concentric loops - the idea is not to proceed to the next load until the first one has completed. I think - someone can correct me if I'm wrong, that the file system cannot do simultaneous reads. If there is an accepted and secure example of how to do this I would still love to hear about it, so I'm not answering my own question.
#include <wrl.h>
#include <robuffer.h>
uint8_t* GetBufferData(winrt::Windows::Storage::Streams::IBuffer& buffer)
{
::IUnknown* unknown = winrt::get_unknown(buffer);
::Microsoft::WRL::ComPtr<::Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
HRESULT hr = unknown->QueryInterface(_uuidof(::Windows::Storage::Streams::IBufferByteAccess), &bufferByteAccess);
if (FAILED(hr))
return nullptr;
byte* bytes = nullptr;
bufferByteAccess->Buffer(&bytes);
return bytes;
}
https://learn.microsoft.com/en-us/cpp/cppcx/obtaining-pointers-to-data-buffers-c-cx?view=vs-2017
https://learn.microsoft.com/en-us/windows/uwp/xbox-live/storage-platform/connected-storage/connected-storage-using-buffers
A 2012 answer at StackOverflow (“How do I read a binary file in a Windows Store app”) suggests this method of reading byte data from a StorageFile in a Windows Store app:
IBuffer buffer = await FileIO.ReadBufferAsync(theStorageFile);
byte[] bytes = buffer.ToArray();
That looks simple enough. As I am working in cppwinrt I have translated that to the following, within the same IAsyncAction that produced a vector of StorageFiles. First I obtain a StorageFile from the VectorView using theFilesVector.GetAt(index);
//Then this line compiles without error:
IBuffer buffer = co_await FileIO::ReadBufferAsync(theStorageFile);
//But I can’t find a way to make the buffer call work.
byte[] bytes = buffer.ToArray();
“byte[]” can’t work, to begin with, so I change that to byte*, but then
the error is “class ‘winrt::Windows::Storage::Streams::IBuffer’ has no member ‘ToArray’”
And indeed Intellisense lists no such member for IBuffer. Yet IBuffer was specified as the return type for ReadBufferAsync. It appears the above sample code cannot function as it stands.
In the documentation for FileIO I find it recommended to use DataReader to read from the buffer, which in cppwinrt should look like
DataReader dataReader = DataReader::FromBuffer(buffer);
That compiles. It should then be possible to read bytes with the following DataReader method, which is fortunately supplied in the UWP docs in cppwinrt form:
void ReadBytes(Byte[] value) const;
However, that does not compile because the type Byte is not recognized in cppwinrt. If I create a byte array instead:
byte* fileBytes = new byte(buffer.Length());
that is not accepted. The error is
‘No suitable constructor exists to convert from “byte*” to “winrt::arrayView::<uint8_t>”’
uint8_t is of course a byte, so let’s try
uint8_t fileBytes = new uint8_t(buffer.Length());
That is wrong - clearly we really need to create a winrt::array_view. Yet a 2015 Reddit post says that array_view “died” and I’m not sure how to declare one, or if it will help. That original one-line method for reading bytes from a buffer is looking so beautiful in retrospect. This is a long post, but can anyone suggest the best current method for simply reading raw bytes from a StorageFile reference in cppwinrt? It would be so fine if there were simply GetFileBytes() and GetFileBytesAsync() methods on StorageFile.
---Update: here's a step forward. I found a comment from Kenny Kerr last year explaining that array_view should not be declared directly, but that std::vector or std::array can be used instead. And that is accepted as an argument for the ReadBytes method of DataReader:
std::vector<unsigned char>fileBytes;
dataReader.ReadBytes(fileBytes);
Only trouble now is that the std::vector is receiving no bytes, even though the size of the referenced file is correctly returned in buffer.Length() as 167,513 bytes. That seems to suggest the buffer is good, so I'm not sure why the ReadBytes method applied to that buffer would produce no data.
Update #2: Kenny suggests reserving space in the vector, which is something I had tried, this way:
m_file_bytes.reserve(buffer.Length());
But it didn't make a difference. Here is a sample of the code as it now stands, using DataReader.
buffer = co_await FileIO::ReadBufferAsync(nextFile);
dataReader = DataReader::FromBuffer(buffer);
//The following line may be needed, but crashes
//co_await dataReader.LoadAsync(buffer.Length());
if (buffer.Length())
{
m_file_bytes.reserve(buffer.Length());
dataReader.ReadBytes(m_file_bytes);
}
The crash, btw, is
throw hresult_error(result, hresult_error::from_abi);
Is it confirmed, then, that the original 2012 solution quoted above cannot work in today's world? But of course there must be some way to read bytes from a file, so I'm just missing something that may be obvious to another.
Final (I think) update: Kenny's suggestion that the vector needs a size has hit the mark. If the vector is first prepared with m_file_bytes.assign(buffer.Length(),0) then it does get filled with file data. Now my only worry is that I don't really understand the way IAsyncAction is working and maybe could have trouble looping this asynchronously, but we'll see.
The array_view bridges the gap between Windows APIs and C++ array types. In this example, the ReadBytes method expects the caller to provide some array that it can copy bytes into. The array_view forwards a pointer to the caller's array as well as its size. In this case, you're passing an empty vector. Try resizing the vector before calling ReadBytes.
When you know how many bytes to expect (in this case 2 bytes), this worked for me:
std::vector<unsigned char>fileBytes;
fileBytes.resize(2);
DataReader reader = DataReader::FromBuffer(buffer);
reader.ReadBytes(fileBytes);
cout<< fileBytes[0] << endl;
cout<< fileBytes[1] << endl;
I want to save the contents of a ComboBox to a file. The code below correctly shows a MessageBox with "Marker 4" (the text in the ComboBox), but the saved file contains "03038D8C" instead of "Marker 4", I guess this is the memory address of the variable or something similar? How can I correctly output the "Marker 4"-string to the file?
private: System::Windows::Forms::ComboBox^ cmbMarker;
private: System::String^ strMarkerText;
...
strMarkerText = this->cmbMarker->Text;
...
ofstream myfile;
WIN32_FIND_DATA data;
pin_ptr<const wchar_t> wname = PtrToStringChars(strMarkerText);
FindFirstFile(wname, &data);
::MessageBox(0, wname, L"Marker inserted", MB_OK);
myfile <<"=====MARKER '" << wname << "' INSERTED AT " << datetime << " =====" << endl;
[There may be more than this wrong with this snippet, I'm not from a C++/CLI background but appreciate your help! There are no compiler errors and the code runs fine except for the issue described above, i.e. that not the cleartext-string-contents are written to the file ("Marker 4"), but "03038D8C".]
Thanks,
Nick
The problem is that you're using a narrow stream with a wide string. Use std::wofstream instead of std::ofstream and it should work fine.
That being said, I agree with #jonsca -- why drag iostreams into a C++/CLI app?
I'm not sure of your application's requirements, but have you considered using the .NET "equivalents" of the functions, like System::IO::Directory methods (specifically GetFiles in place of FindFirstFile), and the System::IO::StreamWriter in place of the ofstream object? This way the code in this section jives with the CLR portion of your code.
I know that's not precisely what you were asking for, but I have a feeling that the pointer in your code might need to be handled differently, and I'm unsure if would have to be marshaled across the managed/unmanaged barrier.
I ended up converting the System::String^ to a std:str and directly inserted this (rather than converting it to a wchar_t).
The mix between native c++ and CLI is because I'm building on a SDK-example built in native c++, but wanted to add a form to it (in Visual Studio 2008), which turned it into this "mix". I realize that that's not optimal, but so far, it seems to work :-)! I'll try to only use CLI-equivalents if I run into any more errors going forward. Thanks for your help!