The files in the above list are not from all jpg files in a folder, but from
This file.
Merging multiple files into one file is very useful in many application fields. Self-implementation of such a program will not only be enjoyable, but will often help us build more efficient programs. Here I will share my case with you.
Because the merged file is like a package, this file is called "package file" in the following sections"
Main Idea:
To Merge multiple files into a package file, you can also distinguish a file and extract it. We need to know the file name and the location and length of the file in the package file, that is, the so-called address offset.
Because the package file is often large, you should not keep its content in the memory. Instead, you must extract some of the content from the package file.
I did this:
A manager class that provides some peripheral Methods
_ PathList is used to store the file path to be added to the package file. You can call AddSourceFile () to add
_ Pf is a specific package file. An instance is generated through LoadPackFile () and returned through the CurrentPackFile attribute.
The Build method is used to generate package files.
The PackFile class is a nested class of PackFileManager. It provides the attributes and construction details of the package file.
Okay. Let's take a look at the PackFileManager. Build () method.
Copy codeThe Code is as follows:
Public void Build (string path)
{
Using (FileStream fs = new FileStream (path, FileMode. Create, FileAccess. Write ))
{
BinaryWriter bw = new BinaryWriter (fs );
Bw. Write ("PackFile ");
Bw. Write (this. _ pathList. Count );
Foreach (string f in this. _ pathList)
{
FileInfo fi = new FileInfo (f );
Bw. Write (fi. Length );
Fi = null;
}
Foreach (string f in this. _ pathList)
{
Bw. Write (Path. GetFileName (f ));
}
Foreach (string f in this. _ pathList)
{
Bw. Write (File. ReadAllBytes (f ));
Bw. Flush ();
}
}
}
1. First write a "PackFile" string to the file header
2. Write the Int32-type file to the number of files to be output to the package file
3. Write the length of each file to be output to the package file of the long type.
4. Write each file name
5. Finally, the object content of each file is written.
Since the Write or read operations are not frequently switched between different versions of the Write or ReadXXX methods, I think the file structure can be more efficient.
Question. When writing a file name, we use bw. Write (Path. GetFileName (f ));
If BinaryWriter. Write (string value) is called and the input is a string, BinaryReader. ReadString () must be called during read (). How does one differentiate the boundary of two strings. Fortunately, the Write method will first Write the string length as a four-byte unsigned integer, so BinaryReader is used. when ReadString () is used, it will read the value of a specific length based on this value and understand it as a string.
Several important methods are listed here:
Copy codeThe Code is as follows:
PackFileManager LoadPackFile Method
Public void LoadPackFile (string path)
{
If (! File. Exists (path ))
{
Throw new FileNotFoundException (path );
}
If (_ pf! = Null)
{
_ Pf. Close ();
_ Pf = null;
}
FileStream fs = new FileStream (path, FileMode. Open, FileAccess. Read );
BinaryReader br = new BinaryReader (fs );
If (br. ReadString ()! = "PackFile ")
{
Throw new InvalidCoalescentFileException ("this file is not a valid package file ");
}
This. _ pf = new PackFile (fs, br );
}
In this case, the "PackFile" string we write during production has a clear function.
PackFile Constructor
Copy codeThe Code is as follows:
Internal PackFile (FileStream srcFile, BinaryReader br)
{
This. _ sourceFile = srcFile;
_ Br = br;
This. _ fileCount = _ br. ReadInt32 (); // obtain the number of files
For (int I = 1; I <= _ fileCount; I ++)
{
This. _ fileLengthList. Add (_ br. ReadInt64 ());
}
For (int I = 1; I <= _ fileCount; I ++)
{
This. _ shortNameList. Add (_ br. ReadString ());
}
This. _ contentStartPos = _ sourceFile. Position; // you can specify the starting Position of an object.
}
PackFile. GetBytes ()
Copy codeThe Code is as follows:
Public byte [] GetBytes (int index)
{
Long startPos = this. _ contentStartPos;
For (int I = 0; I <index; I ++)
{
StartPos + = this. _ fileLengthList [I];
}
_ SourceFile. Position = startPos; // you can specify the starting Position of a file.
Return _ br. ReadBytes (int) _ fileLengthList [index]);
}
This is just a draft. We can also add compression or nested folder functions like ZIP files. Don't forget to share the improved code with me.