How to create a file containing files and director

2020-03-08 07:06发布

问题:

I am working on a WPF open source markdown editor and I am at the point where I need to save and load documents.

A "document" contains 3 files:

  • A XML file for metadata
  • A MD file for the markdown text
  • A HTML file for the HTML view of the document.

At this point for testing I create a directory for each document to hold these files, however this is not very convenient. I need all those files to be packaged inside a single file so users wouldn't be confused with 3 separate files.

I did a bit of research and found out office documents have a similar structure where each file is actually a package that holds multiple directories and files. To open such an office document all you need to do change the extension to ZIP and you can browse the files, but on the outside it looks as a single file.

My initial idea was to zip all the files to a single file, change extension when saving. And unzip it when I am actually loading the file. But I felt this approach was not very elegant.

Is there any elegant way to archive multiple files and directories into a single file and access them I need them in C#?

Any advice would be appreciated.

回答1:

You were right to consider zipping the files (you don't want to reinvent that wheel), and you were also right that unzipping to the filesystem is ugly. But you don't have to; you can create the zip and pull files out of it entirely in your own code with the ZipArchive class.



回答2:

If anyone is wondering how I applied Ed Plunkett's answer, here is the code:

var saveDialog = new SaveFileDialog
{
    CreatePrompt = true,
    OverwritePrompt = true,
    Filter = "Project Markdown File | *.pmd"
};

var result = saveDialog.ShowDialog();

if (result != null)
{
    if (result == true)
    {
        if (!Directory.Exists(saveDialog.FileName + "_temp"))
        {
            var parentFolder = Directory.CreateDirectory(saveDialog.FileName + "_temp").FullName;

            var mp = new MarkdownParser();
            // Generate HTML
            var html = mp.Parse(document.Markdown.Markdown);

            var markdownFilePath = parentFolder + "\\" + saveDialog.SafeFileName + ".md";
            var htmlFilePath = parentFolder + "\\" + saveDialog.SafeFileName + ".html";
            var metadataFilePath = parentFolder + "\\" + saveDialog.SafeFileName + ".xml";
            // Generate MD file
            using (var sw = new StreamWriter(markdownFilePath))
            {
                sw.Write(document.Markdown.Markdown);
            }
            // Generate HTML file
            using (var sw = new StreamWriter(htmlFilePath))
            {
                sw.Write(html);
            }
            // Generate XML file
            document.Metadata.FileName = saveDialog.SafeFileName;
            var gxs = new GenericXmlSerializer<DocumentMetadata>();
            gxs.Serialize(document.Metadata, metadataFilePath);
            // Generate style
            var cssFilePath = AppDomain.CurrentDomain.BaseDirectory + "Styles\\github-markdown.css";
            if (!Directory.Exists(parentFolder + "\\Styles"))
            {
                Directory.CreateDirectory(parentFolder + "\\Styles");
            }

            if (!File.Exists(parentFolder + "\\Styles\\github-markdown.css"))
            {
                File.Copy(cssFilePath, parentFolder + "\\Styles\\github-markdown.css");
            }
            // Generate the package
            ZipFile.CreateFromDirectory(parentFolder, saveDialog.FileName);
            // Update the view
            var saveResult = new SaveResult
            {
                FileName = saveDialog.SafeFileName,
                Source = htmlFilePath.ToUri(),
                TempFile = saveDialog.FileName + "_temp"
            };
            return saveResult;
        }
    }
}