简体   繁体   English

如何从 ArrayList 写入文本文件

[英]How to write to a text file from an ArrayList

I'm trying to take data from an ArrayList of a class and write it into a text file.我正在尝试从类的ArrayList中获取数据并将其写入文本文件。 It creates the temporary file, but doesn't do anything with it.它创建临时文件,但不对它做任何事情。 It prints what I'm trying to put in the file and doesn't delete the temporary file.它会打印我要放入文件的内容,并且不会删除临时文件。 What am I doing wrong?我究竟做错了什么?

try
{
    File temp = new File("temp.txt");
    File file = new File(prop.getProperty("path"));
    BufferedWriter writer = new BufferedWriter(new FileWriter(temp));
    ArrayList<Contact> contacts = gestor.checkData();
                        
    if(temp.createNewFile())
    {
        for(int i = 0; i < contacts.size(); i++)
        {
            writer.write(contacts.get(i).getName());
            writer.write(contacts.get(i).getLastNames());
                                
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            String date = df.format(contacts.get(i).getBirthday());
                                
            writer.write(date);
            writer.write(contacts.get(i).getEmail());
        }
    writer.close();
    file.delete();
    temp.renameTo(file);
    }
}
catch (IOException e)
{
    e.printStackTrace();
}

The code of checkData() just returns the ArrayList<Contact> contactList . checkData()的代码只返回ArrayList<Contact> contactList

Many problems with your code:您的代码存在许多问题:

resource leakage资源泄漏

Something like a new FileWriter is a resource .new FileWriter这样的东西是一种资源 Resources MUST be closed.资源必须关闭。 As a consequence, you should never make resources (you usually know it when you make a resource: you either call new X where X is clearly representative of a resource, or you call something like socket.getInputStream or Files.newBufferedReader ... unless you do it 'right'. There are only two ways to do it right:因此,你永远不应该创建资源(你通常在创建资源时就知道:你要么调用new X其中 X 显然代表资源,要么调用诸如socket.getInputStreamFiles.newBufferedReader类的东西......除非你做对了。只有两种方法可以做到:

try (FileWriter w = new FileWriter(...)) {
   // use it here
}

or, if you need the resource to be a field of your class, then the only safe way is to turn your class into a resource: make it implements AutoClosable , make a close method, and now the burden of using that try syntax is on whomever uses your class.或者,如果您需要资源成为您的类的一个字段,那么唯一安全的方法是将您的类变成一个资源:使其implements AutoClosable ,创建一个 close 方法,现在使用该 try 语法的负担是谁使用你的课。 There is no way to safely do this stuff without try-with-resources *.没有 try-with-resources * 就没有办法安全地做这些事情

Charset messup字符集混乱

files are bytes.文件是字节。 not characters.不是字符。 In addition, the filesystem has no clue what the 'encoding' is.此外,文件系统不知道“编码”是什么。 How do you turn , or for that matter, é into bytes?您如何将或就此而言é转换为字节? The answer depends on charset encoding.答案取决于字符集编码。 The problem with all methods that turn bytes into characters or vice versa that are NOT in the java.nio.file package is that they use 'platform default encoding'.所有将字节转换为字符或反之亦然java.nio.file包中的方法的问题在于它们使用“平台默认编码”。 That's a funny way of saying 'the worst idea ever', as that will 'work' on your machine and will pass all tests, and then fail in production, at the worst possible moment.这是说“有史以来最糟糕的想法”的一种有趣方式,因为这将在您的机器上“工作”并通过所有测试,然后在最糟糕的时刻在生产中失败。 The solution is to never rely on platform default, ever.解决方案是永远不要依赖平台默认值。 If you really really intend to use that, make it explicit.如果您真的打算使用它,请明确说明。 Unfortunately, FileWriter, until java11, has no way of specifying charset encoding, which makes it an utterly useless class you cannot actually ever use without writing buggy code.不幸的是,在 java11 之前,FileWriter无法指定 charset 编码,这使得它成为一个完全无用的类,如果不编写错误代码,您将无法真正使用它。 So don't.所以不要。 I suggest you switch to the new file API, which defaults to UTF-8 (quite a sane default), and can do a lot of complicated things in one-liners.我建议你切换到新的文件 API,它默认为 UTF-8(相当合理的默认值),并且可以在一行中完成很多复杂的事情。

No newlines没有换行符

You just .write all this data.您只需.write所有这些数据。 write does exactly what it says, and writes precisely the string. write 完全按照它所说的去做,并且准确地写入字符串。 It does not print anything more.它不再打印任何东西。 Specifically, it does not print any newlines.具体来说,它不打印任何换行符。 Surely you did not intend to just write, say, JoeSteel1990-10-01 to the file, all in one jumbled mess like that?您肯定不打算只将JoeSteel1990-10-01文件中,像这样一团糟? write \n to avoid this, or preconstruct the entire string just as you want it (with newlines), and then write that.\n来避免这种情况,或者按照你的意愿预先构造整个字符串(使用换行符),然后写下它。

on unexpected condition silently do nothing在意想不到的情况下默默地什么都不做

Your code will silently do nothing if the 'temp' file already exists.如果“临时”文件已经存在,您的代码将不执行任何操作。 It sounds like the design is that this is a weird situation (as the temp file is 'renamed' right after).听起来设计是这是一个奇怪的情况(因为临时文件在之后被“重命名”)。 As a general rule of thumb, 'silently do nothing' is entirely the wrong instinct to have when you run into scenarios you know are unlikely or seemingly impossible.作为一般的经验法则,当您遇到您知道不太可能或看似不可能的情况时,“默默地什么都不做”完全是错误的本能。 The right instinct is the exact opposite: Fail as spectacularly as you can.正确的直觉恰恰相反:尽可能地失败。 (The best option, of course, is to think about what the weird scenario means and handle it properly, but that's not always possible). (当然,最好的选择是考虑奇怪的场景意味着什么并正确处理它,但这并不总是可能的)。 So, instead of that, try:因此,请尝试:

if (!temp.creatNewFile()) {
    throw new RuntimeException("That is weird - tempfile already exists: " + temp);
}

That's the right mindset: If weird things happen, blow up, as fast as you can, with enough detail so you know what's going wrong.这是正确的心态:如果发生了奇怪的事情,请尽快炸毁,并提供足够的细节,以便您知道出了什么问题。 (The most likely 'correct' way to handle this is to just delete the temp file. The whole point of that temp file is that if it's still there when you enter this code, that the previous attempt failed halfway through, so just delete the product of the failed operation, it isn't useful). (最可能的“正确”处理方法是删除临时文件。该临时文件的全部意义在于,如果在您输入此代码时它仍然存在,则之前的尝试中途失败,所以只需删除失败操作的产物,它没有用)。

exception handling.异常处理。

Whilst common in examples and even IDE templates, you're not doing it right.虽然在示例甚至 IDE 模板中很常见,但您做得不对。 You should NEVER handle an exception by printing something and carrying on.你永远不应该通过打印一些东西并继续处理异常。 Think about it: If something went wrong, continuing with the code execution is either going to cause nasty problems (as you surely did not consider that one of the steps in your program failed when you write your code), or is going to cause another error.想一想:如果出现问题,继续执行代码要么会导致严重的问题(因为您在编写代码时肯定没有考虑到程序中的一个步骤失败),或者会导致另一个错误。 And if all errors are handled like this, one thing goes wrong and you get 85 error traces in your logs.如果所有错误都这样处理,那么就会出现一件事,并且您的日志中会出现 85 个错误跟踪。 That's not useful.那没用。 If a problem occurs and you do not know how to handle it, do NOT continue running .如果出现问题而您不知道如何处理,请不要继续运行 The only sensible 'I do not know how to handle this' exception handling is:唯一明智的“我不知道如何处理”异常处理是:

catch (IOException e) {
    throw new RuntimeException("unhandled", e);
}

sometimes a better exception than RuntimeException is possible (such as UncheckedIOException or ServletException, it depends on the situation).有时比 RuntimeException 更好的异常是可能的(例如 UncheckedIOException 或 ServletException,这取决于情况)。 Also, sometimes the right answer is to just throws the exception onwards.此外,有时正确的答案是向前throws异常。 Remember, public static void main can (and usually should!) be declared as throws Exception .请记住, public static void main可以(并且通常应该!)被声明为throws Exception

Putting it all together把它们放在一起

try {
    Path temp = Paths.get("temp.txt");
    Path file = Paths.get(prop.getProperty("path"));
    ArrayList<Contact> contacts = gestor.checkData();

    try (BufferedWriter writer = Files.newBufferedWriter(temp)) {
      for (Contact contact : contacts) {                        
          writer.write(contact.getName());
          writer.write("\n");
          writer.write(contact.getLastNames());
          writer.write("\n");
          DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
          String date = df.format(contact.getBirthday());
          writer.write(date);
          writer.write("\n");
          writer.write(contact.getEmail());
          writer.write("\n");
      }
    }
    Files.delete(file);
    Files.move(temp, file);
} catch (IOException e) {
    throw new UncheckedIOException(e);
}

The above will probably fail, but it will fail telling you exactly why it failed.以上可能会失败,但它会失败告诉你它失败的确切原因。 For example, it might tell you that the directory you are trying to write to does not exist, or you have no write access.例如,它可能会告诉您您尝试写入的目录不存在,或者您没有写入权限。 Whereas your code will then silently just do nothing.而您的代码将默默地什么也不做。

*) For you java pros out there, sure, you can handroll your own try/finally loops. *) 对于您的 java 专业人士,当然,您可以手动处理自己的 try/finally 循环。 Let me know how many programmers new to java ever managed to dodge every mine in the minefield when you do that.让我知道当你这样做时,有多少 Java 新手曾设法避开雷区中的每一个地雷。 Until you are fairly wintered, this rule of thumb becomes effectively a rule of law: You can't do it safely without twr.直到你完全过冬,这条经验法则实际上变成了一条法则:没有 twr,你就无法安全地做到这一点。 Let's keep it simple.让我们保持简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM