java 如何编写和读取多个单行和多行字符串

1zmg4dgp  于 2023-09-29  发布在  Java
关注(0)|答案(6)|浏览(112)

我有一个字符串列表

List<String> strings = new ArrayList<>();

我想在这个列表中存储单行和多行字符串,然后将它们保存到文件中

public static void storeToFile(List<String> strings, String fileName) {}
public static List<String> fromFile(String fileName) {}

chcabym mógū uzyskać noweg.

strings.add("something");
strings.add("I\nlike\nto\nride\nhorses\nsometimes");
strings.add("its ok");

我正在寻找一个关于如何在文件中分隔这些字符串的想法,我排除使用分隔符,因为如果用户输入一个字符串也是分隔符,我也排除计算字符串之前的行。我知道JSON可以做到这一点,但还有其他选择吗?

xmd2e60i

xmd2e60i1#

如果要在文件中同时存储单行和多行字符串,而不使用分隔符,也不预先计算行数,则可以使用一种格式,在字符串本身之前对每个字符串的长度进行编码。实现此目的的一种方法是使用二进制格式,其中每个字符串前面都有一个固定大小的整数,以字节表示其长度。
下面是一个如何使用此方法实现storeToFile和fromFile方法的示例:

public static void storeToFile(List<String> strings, String fileName) {
    try (DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(fileName))) {
        for (String str : strings) {
            byte[] bytes = str.getBytes("UTF-8");
            int length = bytes.length;
            outputStream.writeInt(length); // Write the length
            outputStream.write(bytes);     // Write the bytes
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static List<String> fromFile(String fileName) {
    List<String> strings = new ArrayList<>();
    try (DataInputStream inputStream = new DataInputStream(new FileInputStream(fileName))) {
        while (inputStream.available() > 0) {
            int length = inputStream.readInt(); // Read the length
            byte[] bytes = new byte[length];
            inputStream.readFully(bytes);       // Read the bytes
            String str = new String(bytes, "UTF-8");
            strings.add(str);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return strings;
}

public static void main(String[] args) {
    List<String> strings = new ArrayList<>();
    strings.add("something");
    strings.add("I\nlike\nto\nride\nhorses\nsometimes");
    strings.add("its ok");

    storeToFile(strings, "strings.dat");

    List<String> loadedStrings = fromFile("strings.dat");
    for (String str : loadedStrings) {
        System.out.println(str);
    }
}

在本例中,每个字符串都存储为一系列字节,其长度在字符串之前编码为整数。这种方法确保您可以正确地分隔字符串,而不管它们的内容如何,包括换行符或其他可用作分隔符的字符。

8e2ybdfx

8e2ybdfx2#

好吧,为字符串使用分隔符是一种选择--但为什么呢?
如何在多行字符串中转义换行符?

try( final var output = new PrintStream( file ) )
{
  for( final var string : strings )
  {
    output.println( string.replace( "\n", "\\n" ) );
    // If your string contains backslashes, try this instead:
    // output.println( string.replace( "\\", "\\\\" ).replace( "\n", "\\n" ) );    
  }
}

(最初,代码使用String#replaceAll,但正如@erickson在评论中指出的那样,这是使用Regex,不会按预期工作)
阅读更简单:

final List<String> strings = Files.lines( file.toPath )
  .map( String::translateEscapes )
  .toList();

或者使用Base64在文件中存储字符串呢?
像往常一样,我省略了所需的错误处理。

wn9m85ua

wn9m85ua3#

通常,文本数据的默认分隔符是换行符。由于您希望换行符包含在单个字符串的表示中,因此可以使用新的分隔符来实现这一点。
例如,您对在文本文件中存储以下数据感兴趣

something
I
like
to
ride
horses
sometimes
its ok

但是,在您的应用程序中,您希望具有以下内容
string_A = "something"
string_B = "I\nlike\nto\nride\nhorses\nsometimes"
string_C = "its ok"
正如您已经发现的,尝试逐行读取文本文件将很难在原始数据结构中保留多行字符串。实现此目的的一种方法是为字符串使用分隔符。假设分隔符是分号;。然后,您的文本文件可能看起来像这样:

something;
I
like
to
ride
horses
sometimes;
its ok;

然后你可以定义你的读和写函数,在写数据和解析数据时使用分隔符:

public static void storeToFile(List<String> strings, String fileName, String delimiter = ";") {}
public static List<String> fromFile(String fileName, String delimiter = ";") {}

storeToFile方法会在字符串写入文件时将分隔符添加到字符串。fromFile方法将向上读取,直到遇到分隔符,而不是逐行阅读。
这将帮助您保存原始数据。
如果用户输入的字符串也是一个分隔符,会怎么样
您可以使用特殊字符或非打印字符来帮助避免这种情况,例如空字节(delimiter = "\x00")。您还可以提前验证字符串,以确保分隔符不在其中。在这些情况下,它有助于将用户的文本限制为预定义的字符集。

备选方案

如果您正在寻找一种更快的方法,您还可以在写入文件时简单地序列化ArrayList,并在阅读时将其重新序列化。但是,这将导致序列化的工件出现在文本文件中,并且如果您打开文件,它将不会读取如下内容:

something
I
like
to
ride
horses
sometimes
its ok

相反,您会发现元数据将ArrayList表示为序列化的实体。

olhwl3o2

olhwl3o24#

我建议使用常规的行尾转义符,即反斜杠或\字符。
写入文件时,在用户输入中的每个换行符和反斜杠字符之前插入\。阅读文件时,将以反斜杠结尾的行连接到一个字符串中,并将任何双反斜杠序列替换为一个反斜杠。

kse8i1jr

kse8i1jr5#

下面是一些数据行,每个嵌入的行结束符都使用双反斜杠\\进行转义。保留尾随行结束符以分隔行分组。

List<String> lines = List.of("To be or not to\\nbe that is the question.\n",
        "When in the course\\nof human events it becomes\\nnecessary...\n",
        "A single line");

写入文件

try (FileWriter fw = new FileWriter("f:/Text.txt")) {
   for (String line : lines) {
       fw.write(line);
   }
    
} catch (IOException ioe) {
    ioe.printStackTrace();
}

从文件中读取并打印

try (Scanner scanner = new Scanner(new File("F:/Text.txt"))) {
    while (scanner.hasNextLine()) {
        String line = scanner.nextLine().replace("\\n","\n");
        System.out.println(line);
        System.out.println("-----------------------");
    }
}  catch (IOException ioe) {
    ioe.printStackTrace();
}

指纹

To be or not to
be that is the question.
-----------------------
When in the course
of human events it becomes
necessary...
-----------------------
A single line
-----------------------

另一种方法是正常地写行,然后写一个空白行。阅读时,只需检查该行是否为空白并进行相应处理。当然,如果您想将空白行作为嵌入的空白行包含进来,这是行不通的。

9gm1akwq

9gm1akwq6#

  • "...我正在寻找一个关于如何在文件中分隔这些字符串的想法,我排除使用分隔符,因为如果用户输入一个字符串也是分隔符..."*

这不是一个困难的实现。
尽管如此,使用双斜杠\\ * 将是这里的最佳解决方案。
这里有一个例子。
利用 String#split 方法来划分新行代码中的文本,并将每行用引号括起来存储在一行中,用逗号分隔。
此外,确保将任何"字符替换为\"

public static void storeToFile(List<String> strings, String fileName) throws IOException {
    try (PrintWriter w = new PrintWriter(new FileWriter(fileName))) {
        for (String s : strings) w.println(parse(s));
        w.flush();
    }
}

static String parse(String s) {
    StringBuilder sb = new StringBuilder();
    int i = 0;
    for (String ss : s.split("\\R")) {
        if (i++ != 0) sb.append(',');
        sb.append('"');
        sb.append(ss.replace("\"", "\\\""));
        sb.append('"');
    }
    return sb.toString();
}

在阅读文件时,截断引号,并在","序列上 split
注意,这里实际的 regex(?<!\\)\",\"

public static List<List<String>> fromFile(String fileName) throws IOException {
    try (Scanner sc = new Scanner(new File(fileName))) {
        List<List<String>> strings = new ArrayList<>();
        String s;
        while (sc.hasNextLine()) {
            s = sc.nextLine();
            s = s.substring(1, s.length() - 1);
            strings.add(List.of(s.split("(?<!\\\\)\",\"")));
        }
        return strings;
    }
}

示例用法。

List<String> strings = new ArrayList<>();
strings.add("something");
strings.add("I\nlike\nto\nride\nhorses\nsometimes");
strings.add("its ok");
storeToFile(strings, "file.txt");
List<List<String>> list = fromFile("file.txt");
list.forEach(System.out::println);

file.txt

"something"
"I","like","to","ride","horses","sometimes"
"its ok"

输出

[something]
[I, like, to, ride, horses, sometimes]
[its ok]

相关问题