【问题标题】:C# read/write in case sensitive pathC# 在区分大小写的路径中读/写
【发布时间】:2017-06-28 00:19:27
【问题描述】:

我有问题。

我从网络上保存 json,在我电脑上的 json 文件中,这个 json 文件的名称,就是 json 的网址。 为此,我将 web json 转换为字符串,然后将其附加到一个文件中,File.AppendAllText(path, content) 一段时间后,我还需要使用File.ReadAllText(path)从这个文件中读取json

我的问题是有时候,两个json的名字很相似,例如:

*com/doc/BACr 和 *com/doc/BAcr

问题,File类的方法中给出的路径区分大小写,我在同一个文件中写了两次,破坏了它。

我在互联网上找到了 File.Exists(path) 方法的相同问题的解决方案,但没有什么可以替代我用来读取或写入的方法。

你们中的任何人都知道路径上区分大小写的设置,甚至是另一种方法吗?

谢谢

编辑:我显然在 Windows 上工作 :(

Edit bis : 不能修改文件名,因为在其他一些json中,有web路径的引用,当我再次播放我的本地jsons时,如果文件名被修改了,就找不到了。这就是我需要使用区分大小写的路径进行读写的原因。

【问题讨论】:

  • 问题是windows的路径不区分大小写。
  • 以某种方式对文件名进行编码是否可行?是否要求以后能够使用 URL 来检索文件?
  • 如果文件名存在,尝试添加时间戳。
  • Windows 可以实际上处理区分大小写的文件系统(并且 NTFS 保留大小写),但它不是在 Win32 子系统上运行的任何代码的默认设置,并且从 C# 访问它绝不是微不足道的。解决这个问题更实际。例如,您可以将文件的 ASCII 字符转换为十六进制字符串并将其用作名称,在转换回来时保留大小写。
  • 您可以将路径转换为base64。所以对于具有大小写差异的相同字符串也是唯一的

标签: c# json


【解决方案1】:

您需要使您的文件独一无二的东西,同时当您想读回这些文件时,您需要一些东西来重建这种独特性。

假设您的两个文件分别命名为“BAcr”和“BACr”。你可以得到这两个字符串的HashCode,你会得到两个不同的值

string file1 = "BAcr";
int file1Hash = file1.GetHashCode(); //742971449
string file2 = "BACr";
int file1Hash = file2.GetHashCode(); //-681949991

现在,如果您将此哈希码连接到您的文件名,您将获得两个不同的文件,您将能够为相同的输入文件名重新计算相同的哈希码

string newFile1 = $"{file1}.{file1Hash}";
string newFile2 = $"{file2}.{file2Hash}";

您将在这两个重新计算的文件名中保存您的数据,当您需要重新加载它们时,您可以使用相同的技巧从相同的输入“BAcr”或“BACr”开始获取用于保存数据的文件名。

但是string.GetHashCode doesn't guarantee uniqueness在它的结果中,仍然使用相同的一般思想Jeroen Mostert使用这种方法从输入值中获取唯一代码

string unique1 = string.Join("", file1.Select(c => char.IsUpper(c) ? "1" : "0"))
string newFileName1 = $"{file1}.{unique1}";

【讨论】:

  • 如果您知道哈希码不是唯一的,为什么还要使用它?我还没有调查String.GetHashCode 以查看是否有任何冲突可能发生在字符串不同的情况下,但我一开始并不想依赖它。它只需要一次碰撞。除非文件名非常长,否则我更喜欢它们的 Base64 编码版本。作为奖励,它可以对文件系统无法处理的所有内容(包括禁止字符)进行编码,并且可以进行往返,而哈希不会。
  • 是的,你可能是对的。重新阅读上面发布的链接中的答案,不亚于 E.Lippert 现在我对这个解决方案有同样的疑问。
  • 如果您坚持保持可读文件名,并且您只担心大小写,那么String.Join("", "abcABC".Select(c => char.IsUpper(c) ? "1" : "0")) 会以往返的方式明确记录每个字符的大小写。 abcABC.000111 将是修改后的名称。
  • @JeroenMostert 那更好,请尽快发布您的答案,我会删除我的。
  • @Steve:随意窃取我的想法,它首先是基于你的。 :-) 考虑到他们额外的 cmets,我不确定它是否会帮助 OP。
【解决方案2】:

Windows 路径确实不区分大小写,因此您不能拥有这些文件名。

如果文件名已经存在,一个解决方案是更改文件名... 例如;

if (File.Exists(fileNameToSaveTo)){
    // Note: Your example file names did not have an extension,
    //       but if they do, you will need to first extract that then add it back on
    fileNameToSaveTo = fileNameToSaveTo + "1";
}

如果使用此解决方案,您还必须更新您的程序用于在以后从文件中读回的任何标识符......因为您没有发布任何代码我无法猜测它采用什么形式,但是希望你明白吗?

编辑: 重新阅读您的问题后...看来您使用的是 AppendAllText... 在这种情况下,这不应该像您建议的那样“损坏”文件,而应该只是将内容添加到文件的末尾?这不是你观察到的吗?

编辑2: 在读取 cmets Iomed 之后 - 您可以在写入文件之前在写入文件名上使用 Convert.ToBase64String,在读取文件之前在读取函数中对文件名使用 Convert.FromBase64String。这将允许文件名根据大小写而有所不同。

另一种选择是解析 JSON(新文件和现有文件)并将对象添加到数组中,然后将其写入文件,避免您的“损坏”问题?

【讨论】:

  • 是的,但是对于 Json,当我在第一个末尾添加我的 json 时,它会损坏,因为该文件包含 2 个 json 对象,而不是一个 :(
  • 您可以解析 JSON(新文件和现有文件)并将对象添加到数组中,然后将其写入文件?
  • @ThibaultJouan 查看我的 Edit2 了解两种可行的解决方案
【解决方案3】:

给定路径:PathApatha

对于两个文件,使用 base64 技巧:

string PathToFile(string url) =>  System.Convert.ToBase64String(Encoding.UTF8.GetBytes(url));

所以:

Console.WriteLine(PathToFile("pathA")); //cGF0aEE=
Console.WriteLine(PathToFile("patha")); //cGF0aGE=

【讨论】:

    猜你喜欢
    • 2015-06-06
    • 1970-01-01
    • 2018-03-29
    • 2021-11-16
    • 2019-10-12
    • 2011-10-06
    • 2010-09-28
    • 1970-01-01
    • 2021-02-27
    相关资源
    最近更新 更多