首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将上传的文件存储在文件系统中?

如何将上传的文件存储在文件系统中?
EN

Stack Overflow用户
提问于 2008-10-22 10:00:02
回答 5查看 575关注 0票数 0

我正试图找出将用户上传的文件存储在文件系统中的最佳方法。这些文件范围从个人文件到wiki文件。当然,DB会以某种方式指向这些文件,我还没有弄清楚。

基本要求:

  • 仙女体面的安全,所以人们无法猜出文件名(Picture001.jpg,Picture002.jpg,Music001.mp3 )
  • 容易备份和可镜像(我更喜欢一种方式,这样我就不必每次备份时都要复制整个硬盘。我喜欢只备份最新产品的想法,但我对这里的选择很灵活。)
  • 如果需要,可扩展到多个服务器上的数百万个文件。
EN

回答 5

Stack Overflow用户

发布于 2008-10-22 10:04:32

一种技术是将数据存储在以其内容的散列(SHA1)命名的文件中。这是不容易猜测的,任何备份程序都应该能够处理它,而且它很容易被切分(通过在一台机器上存储从0开始的散列,在下一台机器上以1开始哈希,等等)。

数据库将包含用户分配的名称与内容的SHA1哈希之间的映射。

票数 3
EN

Stack Overflow用户

发布于 2008-10-22 10:11:04

文件名指南,自动展开文件夹层次结构,每个文件夹中的文件/文件夹不超过几千个。备份新文件是通过备份新文件夹来完成的。

您还没有说明所使用的环境和/或编程语言,但下面是一个C# / .net / Windows示例:

代码语言:javascript
运行
复制
using System;
using System.IO;
using System.Xml.Serialization;

/// <summary>
/// Class for generating storage structure and file names for document storage.
/// Copyright (c) 2008, Huagati Systems Co.,Ltd. 
/// </summary>

public class DocumentStorage
{
    private static StorageDirectory _StorageDirectory = null;

    public static string GetNewUNCPath()
    {
        string storageDirectory = GetStorageDirectory();
        if (!storageDirectory.EndsWith("\\"))
        {
            storageDirectory += "\\";
        }
        return storageDirectory + GuidEx.NewSeqGuid().ToString() + ".data";
    }

    public static void SaveDocumentInfo(string documentPath, Document documentInfo)
    {
        //the filestream object don't like NTFS streams so this is disabled for now...
        return;

        //stores a document object in a separate "docinfo" stream attached to the file it belongs to
        //XmlSerializer ser = new XmlSerializer(typeof(Document));
        //string infoStream = documentPath + ":docinfo";
        //FileStream fs = new FileStream(infoStream, FileMode.Create);
        //ser.Serialize(fs, documentInfo);
        //fs.Flush();
        //fs.Close();
    }

    private static string GetStorageDirectory()
    {
        string storageRoot = ConfigSettings.DocumentStorageRoot;
        if (!storageRoot.EndsWith("\\"))
        {
            storageRoot += "\\";
        }

        //get storage directory if not set
        if (_StorageDirectory == null)
        {
            _StorageDirectory = new StorageDirectory();
            lock (_StorageDirectory)
            {
                string path = ConfigSettings.ReadSettingString("CurrentDocumentStoragePath");
                if (path == null)
                {
                    //no storage tree created yet, create first set of subfolders
                    path = CreateStorageDirectory(storageRoot, 1);
                    _StorageDirectory.FullPath = path.Substring(storageRoot.Length);
                    ConfigSettings.WriteSettingString("CurrentDocumentStoragePath", _StorageDirectory.FullPath);
                }
                else
                {
                    _StorageDirectory.FullPath = path;
                }
            }
        }

        int fileCount = (new DirectoryInfo(storageRoot + _StorageDirectory.FullPath)).GetFiles().Length;
        if (fileCount > ConfigSettings.FolderContentLimitFiles)
        {
            //if the directory has exceeded number of files per directory, create a new one...
            lock (_StorageDirectory)
            {
                string path = GetNewStorageFolder(storageRoot + _StorageDirectory.FullPath, ConfigSettings.DocumentStorageDepth);
                _StorageDirectory.FullPath = path.Substring(storageRoot.Length);
                ConfigSettings.WriteSettingString("CurrentDocumentStoragePath", _StorageDirectory.FullPath);
            }
        }

        return storageRoot + _StorageDirectory.FullPath;
    }

    private static string GetNewStorageFolder(string currentPath, int currentDepth)
    {
        string parentFolder = currentPath.Substring(0, currentPath.LastIndexOf("\\"));
        int parentFolderFolderCount = (new DirectoryInfo(parentFolder)).GetDirectories().Length;
        if (parentFolderFolderCount < ConfigSettings.FolderContentLimitFolders)
        {
            return CreateStorageDirectory(parentFolder, currentDepth);
        }
        else
        {
            return GetNewStorageFolder(parentFolder, currentDepth - 1);
        }
    }

    private static string CreateStorageDirectory(string currentDir, int currentDepth)
    {
        string storageDirectory = null;
        string directoryName = GuidEx.NewSeqGuid().ToString();
        if (!currentDir.EndsWith("\\"))
        {
            currentDir += "\\";
        }
        Directory.CreateDirectory(currentDir + directoryName);

        if (currentDepth < ConfigSettings.DocumentStorageDepth)
        {
            storageDirectory = CreateStorageDirectory(currentDir + directoryName, currentDepth + 1);
        }
        else
        {
            storageDirectory = currentDir + directoryName;
        }
        return storageDirectory;
    }

    private class StorageDirectory
    {
        public string DirectoryName { get; set; }
        public StorageDirectory ParentDirectory { get; set; }
        public string FullPath
        {
            get
            {
                if (ParentDirectory != null)
                {
                    return ParentDirectory.FullPath + "\\" + DirectoryName;
                }
                else
                {
                    return DirectoryName;
                }
            }
            set
            {
                if (value.Contains("\\"))
                {
                    DirectoryName = value.Substring(value.LastIndexOf("\\") + 1);
                    ParentDirectory = new StorageDirectory { FullPath = value.Substring(0, value.LastIndexOf("\\")) };
                }
                else
                {
                    DirectoryName = value;
                }
            }
        }
    }
}
票数 3
EN

Stack Overflow用户

发布于 2008-10-22 10:05:14

文件名+ salt的SHA1散列(或者,如果需要,文件内容的哈希)。这使得检测重复文件更容易,但也给服务器带来了更大的压力)。这可能需要一些调整才能是唯一的(即添加上传的UserID或时间戳),而盐分是为了使其不可猜测。

然后,文件夹结构由散列的各个部分组成。

例如,如果散列为"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12“,则文件夹可以是:

代码语言:javascript
运行
复制
/2
/2/2f/
/2/2f/2fd/
/2/2f/2fd/2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

这是为了防止大文件夹(一些操作系统有困难用一百万个文件填充文件夹,因此为散列的部分创建几个子文件夹。有几级?这取决于您期望的文件数量,但2或3通常是合理的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/225088

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档