Java属性反斜杠

65
我正在使用Java Properties读取一个属性文件。一切都正常工作,但是Properties会悄悄地丢弃反斜杠。(即)
original: c:\sdjf\slkdfj.jpg

after: c:sdjfslkdfj.jpg

如何让属性不这样做?

我正在使用代码prop.getProperty(key)

我从一个文件中获取属性,我想避免添加双反斜杠


1
属性文件的语法在此处描述:http://download.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader)。 - David J. Liszewski
反斜杠用于转义字符序列和分割行。另外请注意,在Windows中,您可以使用正常的“/”斜杠来表示路径名。 - David R Tribble
9个回答

57

你看到的问题是由Properties.load()引起的,因为反斜杠在其中被用于特定目的。

逻辑行可能通过使用反斜杠字符 \ 转义行终止符序列来跨越多个相邻的自然行,以保存一个键-元素对的所有数据。

如果你无法使用 CoolBeans 的建议,则可以先将属性文件读取到字符串中,将反斜杠替换为双反斜杠,然后再将其传递给 Properties.load()。

String propertyFileContents = readPropertyFileContents();

Properties properties = new Properties();
properties.load(new StringReader(propertyFileContents.replace("\\", "\\\\")));

2
多行属性值将不再被识别。请查看我的帖子以获取解决方案。 - AlexS

25

请使用双反斜杠 c:\\sdjf\\slkdfj.jpg

Properties props = new Properties();
props.setProperty("test", "C:\\dev\\sdk\\test.dat");
System.out.println(props.getProperty("test"));    // prints C:\dev\sdk\test.dat

更新: 感谢下面的@ewh。显然,Windows可以识别正斜杠。所以,我想你可以让你的用户用正斜杠来写,如果之后需要反斜杠,你可以替换一下。我测试了下面的代码片段,它可以正常工作。

Properties props = new Properties();
props.setProperty("test", "C:/dev/sdk/test.dat");
System.out.println(props.getProperty("test"));   // prints C:/dev/sdk/test.dat

1
我想避免使用双反斜杠,因为我正在从用户编写的文件中获取属性。 - JavaIsGreat
抱歉 - 您最初的帖子中没有提供这些信息。如果您使用的是Windows/DOS文件系统,那么恐怕您就没办法了。 - CoolBeans
2
在Windows系统上,你并不会碰到困难。实际上,在Windows系统中,你可以使用正斜杠来表示路径名。我通常在Java属性文件中这样做,以避免与反斜杠搞混。 - ewh

12

使用 正斜杠(/) 符号。在Java中,文件名中不需要使用反斜杠(\) 符号。


7
如果您在将要加载的属性文件中真的需要反斜杠(例如对于不是文件路径的属性),请为每个反斜杠字符放置\u005c,因为在属性文件中反斜杠会被特殊处理,如@unhillbilly提供的文档所示。
@EJP:如果您想在属性文件中存储NTLM登录ID,则绝对需要反斜杠,其中格式为DOMAIN\USERNAME。这种类型的属性不是文件名,因此正斜杠将无法起作用。
编辑:@Max Nanasy:从上面提到的文档(java.util.Properties load javadoc)中(重点在我)
该方法不会将非法转义字符前的反斜杠字符'\'视为错误;反斜杠会被静默删除。例如,在Java字符串中,序列"\z"会导致编译时错误。相比之下,该方法会静默删除反斜杠。因此,该方法将两个字符序列"\b"视为等同于单个字符'b'。
对我来说,在属性文件中使用反斜杠总是有问题(即使使用双反斜杠'\\'),除非我指定Unicode。

1
为什么要使用\u005c而不是\\\?这种方式既不易读,又输入量更多。 - Max Nanasy
@MaxNanasy 使用反引号 // - Alex
@Alex 对于正斜杠(//)是有效的,但我似乎无法让它对反斜杠(\\)有效。 - Max Nanasy
@frooble,您引用的文档详细说明了属性文件转义和Java字符串字面值转义之间的区别。在Java字符串字面值中,两个反斜杠是有效的转义序列,因此您引用的部分是无关紧要的;即使两个反斜杠不是有效的转义序列,您引用的部分也意味着它将表示一个单独的反斜杠,因为它会自动删除第一个反斜杠。我不知道为什么您对双反斜杠感到困惑,但根据文档,这似乎是转义单个反斜杠的正确方式。 - Max Nanasy
1
@Max Nanasy:OP 询问的是如何从文件中加载属性,而不是通过 Java 字符串字面量设置属性。所引用的 load 文档是用于加载属性文件的。 - frooble
显示剩余4条评论

3
\ 替换为 \\ 如下所示:
c:\sdjf\slkdfj.jpg 

to

c:\\sdjf\\slkdfj.jpg

2

除了Bala R的答案外,我还有以下解决方案,可以保持换行符号在行末反斜杠的语义。

这是我的代码:

private static Reader preparePropertyFile(File file) throws IOException {

    BufferedReader reader = new BufferedReader(new FileReader(file));
    StringBuilder result = new StringBuilder();

    String line;
    boolean endingBackslash = false;

    while ((line = reader.readLine()) != null) {
        line = line.trim();
        if (endingBackslash) {

            // if the line is empty, is a comment or holds a new property
            // definition the backslash found at the end of the previous
            // line is not for a multiline property value.
            if (line.isEmpty()
                    || line.startsWith("#")
                    || line.matches("^\\w+(\\.\\w+)*=")) {

                result.append("\\\\");
            }
        }

        // if a backslash is found at the end of the line remove it
        // and decide what to do depending on the next line.
        if (line.endsWith("\\")) {
            endingBackslash = true;
            line = line.substring(0, line.length() - 1);
        } else {
            endingBackslash = false;
        }
        result.append(line.replace("\\", "\\\\"));
    }
    if (endingBackslash) {
        result.append("\\\\");
    }
    return new StringReader(result.toString());
}

private static Properties getProperties(File file) throws IOException {
    Properties result = new Properties();
    result.load(preparePropertyFile(file));
    return result;
}

1
以下代码将有所帮助:

BufferedReader metadataReader = new BufferedReader(new InputStreamReader(new FileInputStream("migrateSchemaGenProps.properties")));
Properties props = new Properties();
props.load(new StringReader(IOUtils.getStringFromReader(metadataReader).replace("\\", "/")));

1
你需要使用replaceAll,因为属性文件中可能有多个反斜杠。 - Olivier Faucheux
@OlivierFaucheux 这是错误的。请参阅javadoc - AlexS
@OlivierFaucheux 这是错误的。请参阅Javadocreplace替换所有出现的字符。replaceAll不起作用,因为'\'不是有效的正则表达式。 - AlexS

0

在属性文件中使用反斜杠并不是一个好习惯,因为它们是转义字符。

然而:Windows 用户倾向于在任何路径中使用它们... 因此,感谢 Apache Common IO,我们可以在一行代码中解决这个问题:

params.load(new StringReader(IOUtils.toString(paramFile.toURI(), null).replaceAll("\\\\", "/")));

0

你需要三个反斜杠才能获得一个: 例如: key=value1\\value2 在属性文件中会变成 key=value1\value2 在Java属性对象中


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接