none
It is possible to wrap StreamWriter in FileStream

    Question

  • Hello,

    Trying to understand a project that I have to refactor, I found these methods in a kind of repository classes

            public static void CreateAllText(string path, string contenidos, Encoding encoding)
            {
                if (!File.Exists(path))
                {
                    using (FileStream FileText = new FileStream(path, FileMode.Create, FileAccess.Write))
                    {
                        using (StreamWriter sDocwriter = new StreamWriter(FileText, encoding, 1024, false))    
                        {
                            sDocwriter.Write(contenidos);
                        }
                    }
                }
                else
                {
                    throw new ArgumentNullException("Error: file Exists overwrite");
                }
            }
    
            public static void AppendText(string path, string contenidos, Encoding encoding)
            {
                if (File.Exists(path))
                {
                    using (FileStream FileText = new FileStream(path, FileMode.Append, FileAccess.ReadWrite))
                    {
                        using (StreamWriter sDocwriter = new StreamWriter(FileText, encoding, 1024, false))      
                        {
                            sDocwriter.Write(contenidos);
                        }
                    }
                }
                else
                {
                    throw new ArgumentNullException("Error: Not File exists");
                }
            }

    first one write all document, but creates a FileStream and then a StreamWriter

    the other is to append FileStream but Writing in a StreamWriter??? I need a explanation!!

    Thursday, December 6, 2018 10:14 PM

All replies

  • The concept of any "stream" in programming is a steady flow of contiguous data that is not relevant to the IO device, but is relevant to an end user or consuming algorithms.  So there's System.IO.Stream which implements the features and functions common to everything else in System.IO that has the word "stream" in its name, and they're all more or less the same thing.

    So the System.IO.StreamWriter writes to a stream.  The System.IO.StreamReader reads from a stream.  The System.IO.FileStream wrappers around a filesystem IO and includes the functions of both a StreamReader and a StreamWriter.  So where you see new StreamWriter(FileText) you're seeing a new instance of the StreamWriter class being created, initialized with the already set up fields and options from the FileStream instance named FileText.

    It looks like the reason is because you're being allowed to pass a text Encoding parameter, and the StreamWriter exposes a Constructor overload that accepts an encoding parameter too, as well as buffered IO.  Another way to write the same code would require many more lines.

            public static void AppendText(string path, string contenidos, Encoding encoding)
            {
                    FileStream FileText = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                    // Set up a data buffer
                    byte[] encodedBuffer = encoding.GetBytes(contenidos);
                    // Ensure the file writeout cursor is at the end of the file    
                    if (FileText.Length > 0) { FileText.Position = FileText.Length - 1; }
                    // Ensure the file is big enough to accept appended writes
                    FileText.SetLength((FileText.Length + encodedBuffer.Length) - 1);
    
                    // Now because of "buffersize" we have to write a whole bunch of code to emulate a buffer
                    byte[] writeBuffer = new byte[1024];
                    int encodingCursor = 0;
                    do
                    {
                        // Each pass we need to make sure the "writeBuffer" is of adequate size but not too much size
                        // alternately, we could 0-fill the whole buffer every pass just to make sure we got a cleanly
                        // buffered copy.
                        if (writeBuffer.Length > (encodedBuffer.Length - encodingCursor))
                        {
                            // Whenever the remaining data to write is less than the writeBuffer size, shrink the 
                            // write buffer to fit
                            writeBuffer = new byte[(encodedBuffer.Length - encodingCursor)];
                        }
                        // Finally copy the needed data from the encoding buffer
                        Array.Copy(encodedBuffer, encodingCursor, writeBuffer, 0, writeBuffer.Length);
    
                        // Finally we can write the encoded text data
                        FileText.Write(writeBuffer, 0, writeBuffer.Length);
                        // Increment the encode cursor
                        encodingCursor += writeBuffer.Length;
    
                        // Keep looping until the encodingCursor is past the end of encoded data
                    } while (encodingCursor < encodedBuffer.Length);
    
                    FileText.Close();
                    FileText.Dispose();
                    FileText = null;
                    writeBuffer = null;
                    encodedBuffer = null;
            }

    So it's easy to see why someone would opt for the cleaner handoff to a StreamWriter rather than do it all themselves, right?  On top of that, we would hope that the DotNET Library was compiled to native code so it'd do all this junk we're doing a whole lot faster.

    There are other significant issues with your original code.  You're testing if the path already exists, when FileMode.Append should create the file if it doesn't exist.  This may be desired behavior, but just hamstrings your functionality and I can't think of a good reason to do that.  In addition, Append mode allows only FileAccess.Write, never Read, so you'd get an exception trying to instantiate the FileStream.  Perhaps the "snippets" project I use to write these demonstrations uses a different DotNET version than you have, which could explain it if this line of code works for you but not for me.


    It never hurts to try. In the worst-case scenario, you'll learn something.

    Thursday, December 6, 2018 11:29 PM
  • Andrew B. Painter

    The concept of any "stream" in programming is a steady flow of contiguous data that is not relevant to the IO device, but is relevant to an end user or consuming algorithms.  So there's System.IO.Stream which implements the features and functions common to everything else in System.IO that has the word "stream" in its name, and they're all more or less the same thing.

    So the System.IO.StreamWriter writes to a stream.  The System.IO.StreamReader reads from a stream.  The System.IO.FileStream wrappers around a filesystem IO and includes the functions of both a StreamReader and a StreamWriter.  So where you see new StreamWriter(FileText) you're seeing a new instance of the StreamWriter class being created, initialized with the already set up fields and options from the FileStream instance named FileText.

    It looks like the reason is because you're being allowed to pass a text Encoding parameter, and the StreamWriter exposes a Constructor overload that accepts an encoding parameter too, as well as buffered IO.  Another way to write the same code would require many more lines.

            public static void AppendText(string path, string contenidos, Encoding encoding)
            {
                    FileStream FileText = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                    // Set up a data buffer
                    byte[] encodedBuffer = encoding.GetBytes(contenidos);
                    // Ensure the file writeout cursor is at the end of the file    
                    if (FileText.Length > 0) { FileText.Position = FileText.Length - 1; }
                    // Ensure the file is big enough to accept appended writes
                    FileText.SetLength((FileText.Length + encodedBuffer.Length) - 1);
    
                    // Now because of "buffersize" we have to write a whole bunch of code to emulate a buffer
                    byte[] writeBuffer = new byte[1024];
                    int encodingCursor = 0;
                    do
                    {
                        // Each pass we need to make sure the "writeBuffer" is of adequate size but not too much size
                        // alternately, we could 0-fill the whole buffer every pass just to make sure we got a cleanly
                        // buffered copy.
                        if (writeBuffer.Length > (encodedBuffer.Length - encodingCursor))
                        {
                            // Whenever the remaining data to write is less than the writeBuffer size, shrink the 
                            // write buffer to fit
                            writeBuffer = new byte[(encodedBuffer.Length - encodingCursor)];
                        }
                        // Finally copy the needed data from the encoding buffer
                        Array.Copy(encodedBuffer, encodingCursor, writeBuffer, 0, writeBuffer.Length);
    
                        // Finally we can write the encoded text data
                        FileText.Write(writeBuffer, 0, writeBuffer.Length);
                        // Increment the encode cursor
                        encodingCursor += writeBuffer.Length;
    
                        // Keep looping until the encodingCursor is past the end of encoded data
                    } while (encodingCursor < encodedBuffer.Length);
    
                    FileText.Close();
                    FileText.Dispose();
                    FileText = null;
                    writeBuffer = null;
                    encodedBuffer = null;
            }

    So it's easy to see why someone would opt for the cleaner handoff to a StreamWriter rather than do it all themselves, right?  On top of that, we would hope that the DotNET Library was compiled to native code so it'd do all this junk we're doing a whole lot faster.

    There are other significant issues with your original code.  You're testing if the path already exists, when FileMode.Append should create the file if it doesn't exist.  This may be desired behavior, but just hamstrings your functionality and I can't think of a good reason to do that.  In addition, Append mode allows only FileAccess.Write, never Read, so you'd get an exception trying to instantiate the FileStream.  Perhaps the "snippets" project I use to write these demonstrations uses a different DotNET version than you have, which could explain it if this line of code works for you but not for me.


    It never hurts to try. In the worst-case scenario, you'll learn something.


    Andrew B. Painter, aka MR BS

    The code above is another example of your stupidity!

    You don't know what you are doing, but I am able to detect what 99.99% of members of this forum is not.

    The file you write is valid, but the data it contains gets corrupted!

    Do you know why? No?

    So, let me tell you, MR BS: you are another rubbish# coder in this forum; the result is that, every time you write bytes in the buufer, the previous buffer gets corrupted! The more you write, the more it will be corrupted.

    This corruption is caused by this statement:

        if (FileText.Length > 0) { FileText.Position = FileText.Length - 1; }

    As you see MR BS, you're an ignorant ssa eloh and pretender.

        ... and rubbish# coder.

    P.S.: if you don't like the way I treat you, ask the manager of these mvps to ban my account; if you don't succeed, this means my treatment to you, is correct!


    • Edited by ritehere44 Saturday, December 8, 2018 6:43 AM
    Saturday, December 8, 2018 6:42 AM
  • So, let me tell you, MR BS: you are another rubbish# coder in this forum; the result is that, every time you write bytes in the buufer, the previous buffer gets corrupted! The more you write, the more it will be corrupted.

    This corruption is caused by this statement:

        if (FileText.Length > 0) { FileText.Position = FileText.Length - 1; }

    As you see MR BS, you're an ignorant ssa eloh and pretender.

        ... and rubbish# coder.

    P.S.: if you don't like the way I treat you, ask the manager of these mvps to ban my account; if you don't succeed, this means my treatment to you, is correct!


    I take it that you stalk people across multiple threads often, derail threads with petulant flamewars, and have never been banned from MSDN Forums for it.  Also that you're the type who feels better about being unemployable by repeating belittling statements to your betters that someone else once said to you. 

    Finally, please detail the nature of the corruption.  Explain what that line of code should be, and what the difference is between your version and mine.  MSDN readers deserve to know what the right way is!


    It never hurts to try. In the worst-case scenario, you'll learn something.

    Saturday, December 8, 2018 6:54 AM


  • I take it that you stalk people across multiple threads often, derail threads with petulant flamewars, and have never been banned from MSDN Forums for it.  Also that you're the type who feels better about being unemployable by repeating belittling statements to your betters that someone else once said to you. 

    MR BS, I told you are an ssa eloh!

        ... and a rubbish# coder.

    Finally, please detail the nature of the corruption.  Explain what that line of code should be, and what the difference is between your version and mine.  MSDN readers deserve to know what the right way is!




    You don't know where the stream end, idiot! Just that, dude.

    Get back to school.

    P.S.: if you don't like the way I treat you, ask the manager of these mvps to ban my account; if you don't succeed, this means my treatment to you, is correct!


    • Edited by ritehere44 Saturday, December 8, 2018 7:08 AM
    Saturday, December 8, 2018 7:07 AM
  • You don't know where the stream end, idiot! Just that, dude.

    Get back to school.

    P.S.: if you don't like the way I treat you, ask the manager of these mvps to ban my account; if you don't succeed, this means my treatment to you, is correct!


    Well, I don't know what programming language you ever actually used before but in C# (as the example is written in since the Forum is Visual C#) indexing is 0-based.  That means that Stream.Length is actually 1 byte past the end of existing Stream, since byte 1 is at index 0.

    If some belligerent halfwit like yourself were to actually set the stream's position to Stream.Length instead of Stream.Length - 1, then write any more data at all, there would be an extraneous null-terminator in the stream.  At risk of referencing "hardcode," which you've taken me to task for already, that's a 0x00.  In encoded text data that's a real problem.  The problem is especially bad to the point of possibly crashing a low-end text editor if you're using multi-byte encodings, but just in general too.

    Class dismissed.


    It never hurts to try. In the worst-case scenario, you'll learn something.

    Saturday, December 8, 2018 7:18 AM
  • I take it that you stalk people across multiple threads often, derail threads with petulant flamewars, and have never been banned from MSDN Forums for it. 

    Oh, @RiteHere has been banned many, many times! He manages to keep coming back, somehow.

    But, @Andrew … you've had a few pretty bad flame-wars yourself in other threads in the past few days. You've got to ignore this kind of behavior and hope the offending people get banned. If you fan the flames (with bad language or name-calling), you'll end up getting banned too. That was not a threat, I can't ban anybody, I just wanted you to be aware that if flamers and trolls are reported to the "powers that be", they can ban people.

    We should all strive to maintain professionalism here on the forums and not get sucked into fights. I try to (although sometimes I get a bit frustrated).


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Saturday, December 8, 2018 3:23 PM
    Moderator
  • I take it that you stalk people across multiple threads often, derail threads with petulant flamewars, and have never been banned from MSDN Forums for it. 

    Oh, @RiteHere has been banned many, many times! He manages to keep coming back, somehow.

    But, @Andrew … you've had a few pretty bad flame-wars yourself in other threads in the past few days. You've got to ignore this kind of behavior and hope the offending people get banned. If you fan the flames (with bad language or name-calling), you'll end up getting banned too. That was not a threat, I can't ban anybody, I just wanted you to be aware that if flamers and trolls are reported to the "powers that be", they can ban people.

    We should all strive to maintain professionalism here on the forums and not get sucked into fights. I try to (although sometimes I get a bit frustrated).


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    From 2008 to 2013 I engaged in a lot more.  The problem for me is that the disinformation these trash spew out on forums (not just MSDN but StackOverflow and literally everywhere on the internet) can do real, actual, physical harm to consumers of it.  I do not like the idea that a newbie or fledgling programmer may have their growth as a programmer stunted by somebody who is not in fact retarded but chooses to behave as if they are anyway.

    I also won an MCC in 2011 for expanding and clarifying MSDN and TechNET documentation.  If you look into my threads you'll find a very clear picture of someone consistently dedicated to clarity and accuracy, who provides a ratio of at least 2-3 answers (not just posts, but posts that are elected by the OP as the answer) per flamewar, and 4-6 posts (most containing code) which are later elected by Moderators et al as answers even though the OP overlooked them.

    Nobody who I engage in flamewar with can say the same.  Not even close.  In fact, nobody who I engage in flamewar with can even say that they posted anything close to accurate or relevant in the thread where I called them out.

    So if you want to ban me, ban me.  I could care less.  I get paid for being who I am, both in my local area and interstate and internationally, by rational adults who value legitimate contributions and intolerance for disinformation.


    It never hurts to try. In the worst-case scenario, you'll learn something.

    Saturday, December 8, 2018 4:17 PM
  • You misunderstood me, Andrew. I can't ban anyone ... Moderators do not have that power. My intent was only to say that it's best to avoid flame-wars if possible. Someone has to be the "grown-up".  ;0)

    I understand your desire to provide correct and helpful replies to the OP. We all should strive for that and those that don't should be called out on it when they're wrong ... *BUT* in a professional and non-provoking manner! Don't be sucked into name-calling, no matter how many times they do it to you.

    And, believe it or not, sometimes those people actually post valid answers, marked as an answer by an OP and without any name-calling throughout the entire thread. To be honest, though, it seems like the mud-slinging is more prevalent than the answers (at least in the Forums I follow).


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Saturday, December 8, 2018 5:58 PM
    Moderator
  • I understand your desire to provide correct and helpful replies to the OP. We all should strive for that and those that don't should be called out on it when they're wrong ... *BUT* in a professional and non-provoking manner! Don't be sucked into name-calling, no matter how many times they do it to you.

    And, believe it or not, sometimes those people actually post valid answers, marked as an answer by an OP and without any name-calling throughout the entire thread. To be honest, though, it seems like the mud-slinging is more prevalent than the answers (at least in the Forums I follow).


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Yeah.  I've seen ritehere44 do exactly that - post something useful amidst a wall of double-spaced oneliners that contain mostly personal insults and deliberately disguised profanity that would pass a profanity filter and maybe even fool an authority figure who isn't up on internet slang used by 9 year olds, like ssa eloh.

    I'm pretty sure that one helpful bit was a total accident considering he tried to do the same thing over here (literally posted within 90 seconds of the one in the other thread that pointed out a real bug) and was ass-backwards that time.

    So whether Moderators have the power to ban or not, somebody must.  That somebody needs to exercise that responsibility a lot more than they do.  There's literally nothing ritehere44 and others like him can do or say, in the way that they do and say it, that can be anything but toxic to your community and possible future viewership.  People like this are trash and the longer any one of them is allowed to sit around the more trash piles up, and I'm sure you know that when you have a huge pile of trash the heat at the bottom rots everything faster and brings more stink than most people can handle.  Trash also attracts rats and flies and other pests, and those spread disease.  Looking at this person's posts (and a couple of other blatant trolls I've identified these last couple of days since coming back to MSDN), I don't even feel like this is a metaphor.


    It never hurts to try. In the worst-case scenario, you'll learn something.

    Saturday, December 8, 2018 6:15 PM