File and stream (using stream to read and write files)

Source: Internet
Author: User

. NET Framework uses stream models in multiple fields of the framework. Stream is an abstraction that allows you to treat different data sources in a similar way (as a sequential byte stream. All. Net stream classes inherit from the system. Io. Stream class.

A stream can represent the data in the memory buffer, the data obtained from the network connection, the data obtained from the file, or the data to be written to the file.

The following code creates a new file and writes it into a byte array using filestream:

FileStream fileStream = null;
try
{
    fileStream = new FileStream(filename, FileMode.Create);
    fileStream.Write(bytes, 0, bytes.Length - 1);
}
finally
{
    if (fileStream!=null)
    {
        fileStream.Close();
    }        
}

This Code demonstrates how to open a filestream and read its content into a byte array:

FileStream fileStream = null;
try
{
    fileStream = new FileStream(filename, FileMode.Open);
    byte[] dataArray = new byte[fileStream.Length];
    for (int i = 0; i < fileStream.Length; i++)
    {
        dataArray[i] = (byte)fileStream.ReadByte();
    }
}
finally
{
    if (fileStream!=null)
    {
        fileStream.Close();
    }        
}

In itself, streams are not very useful because they work in the form of a single byte or byte array.

Remember to close the stream. It will release the file handle and allow others to access the file. In addition, because the filestream class enables release, it is recommended to use it in the using statement block, which ensures that filestream is immediately disabled when the block ends.

 

Filemode enumerated values:

Append If the file exists, open the file and find the end of the file. Otherwise, create a new file.
Create Specifies that a new file is created by the operating system. If the file exists, it will be overwritten.
Createnew Specifies that a new file is created by the operating system. If the file exists, an ioexception is thrown.
Open Specify the operating system to open an existing file
Openorcreate If the file already exists, open it by the operating system. Otherwise, create a new file.
Truncate Specifies that an existing file is opened by the operating system. After opening, the file is truncated to 0 bytes.

 

Text Files

You can use the streamwriter and streamreader classes in the system. Io namespace to read and write file content. When creating these classes, you only need to pass the underlying stream as a constructor parameter:

FileStream fileStream = new FileStream(@"c:\myfile.txt", FileMode.Create);
StreamWriter w = new StreamWriter(fileStream);

You can also use static methods of the file class and fileinfo class, such as createtext () or opentext () to get a streamwriter or streamreader object:

StreamWriter w = File.CreateText(@"c:\myfile.txt");

This code is equivalent to the previous example.

 

. NET provides a class for each encoding method in the system. Text namespace. When using streamwriter and streamreader, you can specify the encoding to use in the constructor parameters, or directly use the default UTF-8 encoding:

FileStream fileStream = new FileStream(@"c:\myfile.txt", FileMode.Create);
StreamWriter w = new StreamWriter(fileStream, System.Text.Encoding.ASCII);

When processing a file, you must disable it. Otherwise, the update may not be correctly written to the disk and the file cannot be locked. You can call flush () at any time to ensure that all data is written to the disk, because streamwriter caches your data in the memory to optimize performance.

 

Tip:

You can also use the readtoend () method to read the content of the entire file. It returns a string. The file class also has some shortcuts, such as static methods readalltext () and readallbytes (), but they only apply to small files. Large files should not be read into the memory at a time, but should use filestream to read part of the content at a time to reduce the memory load.

 

Binary files

Binary data makes better use of space, but the created files are not readable (basically not readable ). To open a file written in binary, you need to create a new binarywriter:

// The constructor of binarywriter accepts a stream as a parameter.
// You can create a file manually or use the static method of the file class.
BinaryWriter w = new BinaryWriter(File.OpenWrite(@"c:\binaryfile.bin"));

. Net focuses on stream objects, rather than data sources or data targets. That is to say, you can use the same code to write binary data to any type of stream, whether it is a file or other storage media..

Unfortunately, when reading data from a binary stream, you must know the data type to be obtained:

BinaryReader r = new BinaryReader(File.OpenRead(@"c:\binaryfile.bin"));
string str = r.ReadString();
int integer = r.ReadInt32();

 

Upload files

ASP. NET has two controls that allow users to upload files to the web server. After the server receives the data from the uploaded files, your application can determine whether to view, ignore, or save the data to the file system of the backend database or web server.

Controls that can be uploaded are htmlinputfile (hmtl Server Control) and fileupload (ASP. NET web control ). Both represent the <input type = 'file'> HTML Tag. The only real difference is that the fileupload control automatically sets the form encoding to multipart/form data. If you use the htmlinputfile control, you must manually set the <form> label feature. If you do not set the feature, the htmlinputfile control cannot work.

A button control is usually added to the page to send the page back. See the following example:

protected void btnUpload_Click(object sender, EventArgs e)
{
    if (Uploader.PostedFile.ContentLength != 0)
    {
        try
        {
            if (Uploader.PostedFile.ContentLength > 1048576)
            {
                lblStatus.Text = "Too large. This file is not allowed.";
            }
            else
            {
                string destDir = Server.MapPath("~/Upload");
                string fileName = Path.GetFileName(Uploader.PostedFile.FileName);
                string destPath = Path.Combine(destDir, fileName);
                Uploader.PostedFile.SaveAs(destPath);
                lblStatus.Text = "Thank you for submitting your file.";
            }
        }
        catch (Exception err)
        {
            lblStatus.Text = err.Message;
        }
    }
}

 

In addition to saving directly uploaded files to the disk, you can also use the stream model to interact with them. You need to use the fileupload. postedfile. inputstream attribute to obtain access to data:

// Assume that the file is text-based.
StreamReader r = new StreamReader(Uploader.PostedFile.InputStream);
lblStatus.Text = r.ReadToEnd();
r.Close();

 

Tip:

By default, the maximum size of files that can be uploaded is 4 MB. If you try to upload a larger file, you will get a runtime error. You can modify the maxrequestlength attribute set in the

 

File security for multiple users

Although it is easy to create a unique file name, what will happen if you have to access the same file among multiple different requests?

One way is to open the file in shared mode, which will allow multiple processes to access the same file at the same time. To use this technology, you must use a filestream constructor that receives four parameters. It allows you to select filemode:

FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);

This statement allows multiple users to open files for reading at the same time. However, no one can update the file. You can specify different fileaccess values so that multiple users can open the file in read-write mode. At this point, when you write a file, Windows will dynamically lock a small part of the file (or you can use filestream. lock () method to lock the part of a file within a certain byte range). If two users try to write the locked part at the same time, an exception will occur. Web applications require high concurrency, allIt is not recommended to use this technology, and its implementation is very difficult. It also forces you to use low-level byte offset calculation, which can easily produce small and disturbing errors.

 

Tip:

Another technology is very effective when multiple users need to access the same data, especially when the data is frequently used and is not particularly large, it is to load the data to the cache. In this way, multiple users can access data without scruples. If another process is responsible for creating or regularly updating files, file dependencies can be used to invalidate the cache when the files are changed.

 

So multiple users must update files at the same time. What is the solution?

  • Method 1: create a separate user-specific file for each request
  • Method 2: bind the file to another object and use the lock function.

1. Create a unique file name

To avoid conflicts, you can create a directory for each user or add some information to the file name, such as the timestamp, GUID (globally unique identifier), or random number.

private string GetFileName()
{
    string fileName = "user." + Guid.NewGuid().ToString();
 
// Obtain the physical file system path of the root directory of the currently running server application.
    return Path.Combine(Request.PhysicalApplicationPath, fileName);
}

Note:

 GUID is a 128-bit integer. Guids are very useful to programs because they are statistically unique and are widely used in uniquely identified queue tasks, user sessions, and other dynamic information. They also have advantages over numerical sequences that are difficult to guess. GUID is usually represented by a group of lower-case hexadecimal numeric strings.

 

You can use getfilename () to create a safer log program. In this example, all logs are recorded by calling the log () method:

private void Log(string message)
{
    FileMode mode;
    if (ViewState["LogFile"] == null)
    {
        ViewState["LogFile"] = GetFileName();
        mode = FileMode.Create;
    }
    else
    {
        mode = FileMode.Append;
    }
 
    string fileName = ViewState["LogFile"].ToString();
    using (FileStream fs = new FileStream(fileName, mode))
    {
        StreamWriter w = new StreamWriter(fs);
        w.WriteLine(DateTime.Now);
        w.WriteLine(message);
        w.WriteLine();
        w.Close();
    }
}

Each time a page is loaded, a log is recorded:

protected void Page_Load(object sender, EventArgs e)
{
    if (Page.IsPostBack)
    {
        Log("Page posted back.");
    }
    else
    {
        Log("Page loaded for the first time.");
    }
}

The last two button events allow you to delete a log file or display its content:

protected void btnRead_Click(object sender, EventArgs e)
{
    if (ViewState["LogFile"] != null)
    {
        StringBuilder log = new StringBuilder();
        string fileName = ViewState["LogFile"].ToString();
        using (FileStream fs = new FileStream(fileName, FileMode.Open))
        {
            StreamReader r = new StreamReader(fs);
            string line;
            do
            {
                line = r.ReadLine();
                if (line != null)
                {
                    log.Append(line + "<br />");
                }
            } while (line != null);
            r.Close();
        }
        lblInfo.Text = log.ToString();
    }
    else
    {
        lblInfo.Text = "There is no log file";
    }
}
 
protected void btnDelete_Click(object sender, EventArgs e)
{
    if (ViewState["LogFile"] != null)
    {
        File.Delete(ViewState["LogFile"].ToString());
        ViewState["LogFile"] = null;
    }
}

 

2. Lock the File Access Object

In some cases, you need to respond to multiple user activities and update the same file. One way is to use the lock. The basic technology is to create a separate class for all tasks that obtain data. Once this class is defined, you can create a global instance for the class and add it to the application set. Now, you can use the lock Statement of C # To ensure that only one thread can access this object at a time.

For example, assume that you have set the following logger class:

public class Logger
{
    public void LogMessage()
    {
        lock (this)
        {
            // Open file and update it.
        }       
    }
}

The logger Object locks itself before accessing the log file and creating the critical section. This ensures that only one thread can execute the logmessage () code at a time, thus eliminating file conflicts.

However, to make this method take effect, you must ensure that all classes use the same instance of the logger object.. There are several options:

  • In response to the httpapplication. Start event of Global. asax, create a logger class instance and save it to the application set.
  • Add the following code to global. asax to publish a logger instance using a static variable.
private static Logger log = new Logger();
public Logger Log
{
    get { return log; }
}

Now, any page that uses logger to call logmessage () will get an access to it:

Application.Log.LogMessage(myMessage);

Remember,This method is only a poor compensation for the inherent limitations of the file system, it does not allow you to manage more complex tasks. If you want each user to read and write fragments of the same file at the same time, when the file is locked by a client, other requests have to wait. This will definitely reduce the performance of the application.This technology is only applicable to small web applications. For this reason, ASP. NET Applications almost never use file-based logs. On the contrary, they write logs in Windows event logs or databases.

 

Compression

. Net supports data compression in any stream. This technique allows you to compress data written to any file. This class supports gzipstream and deflatestream from the system. Io. Compression namespace. Both classes provide similar efficient lossless compression algorithms.

To use compression, you must package the real stream into a compressed stream. For example, you can encapsulate a filestream (compressed when writing data to a disk) or a memorystream (to compress data in the memory ). When using memorystream, You can compress data before it is stored in a binary field of the database or before it is transmitted to the web service.

Suppose you want to compress the data stored in the file:

FileStream fs = new FileStream(fileName, FileMode.Create);
 
// Compressionmode. Compress enumeration specifies whether to compress or decompress
GZipStream compressStream = new GZipStream(fs, CompressionMode.Compress);
 
// When writing real data, use the write () of the compressed stream instead of the write () of filestream ()
// If you want to use a higher level writer, you can provide a compressed stream instead of filestream.
StreamWriter w = new StreamWriter(compressStream);
w.WriteLine();
w.Flush();
fs.Close();

Reading a file is simple. The difference lies in the selection of enumeration values:

FileStream fs = new FileStream(fileName, FileMode.Open);
GZipStream decompressStream = new GZipStream(fs, CompressionMode.Decompress);
StreamReader r = new StreamReader(decompressStream);

File and stream (using stream to read and write files)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.