我正在尝试编写一个程序,用户可以:1)向联系人添加人员(姓名,电话,电子邮件),2)从联系人中删除一个人,3)从联系人中读取所有人。
我这样做的方式是我要求用户选择并分别做任何事情。对于写入,我只是将一个对象写入该文件。为了删除,我想我会问用户“姓”将用作KEY(因为我正在使用TreeMap)并将删除键上的值(对象)。
所以我在这里读书时遇到了问题。我正试图读取这样的对象:
public void readContact()
{
TreeMap<String, Contact> contactMap = new TreeMap<String, Contact>();
try
{
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(
new FileInputStream(file)));
while( in.available() > 0 ) //This line does NOT read
{
Contact c = (Contact)in.readObject();
contactMap.put(c.getLastName(), c);
}
for(Map.Entry contact : contactMap.entrySet() )
{
Contact con = contactMap.get( contact.getKey() );
System.out.println( con.getLastName() + ", " + con.getFirstName() + ": " + con.getPhoneNumber() + "\t" + con.getEmail());
}
}
catch(Exception e)
{
System.out.println("Exception caught");
}
}
在获得while(true)
之前,请不要建议您执行EOFException
之类的操作,因为:
答案 0 :(得分:6)
在我收到EOFException之前,请不要建议做像while(true)这样的事情
这正是我的建议。当您在寻找答案时,根据这样的任意标准限制解决方案空间会适得其反。
,因为:
这不是我相信的异常处理
当您正在调用的API抛出异常时,就像这样,您没有任何选择,只能抓住它。无论您如何看待'异常处理是什么',当他们设计API时,您将受到设计者认为的影响。
在此之后我还有更多的事要做,所以我不能让程序终止'
所以不要终止它。 Catch EOFException,
关闭输入,然后突破循环。
我看到更多的编程时间浪费在'异常处理'上,而不是我真正可以信任的。
答案 1 :(得分:2)
我知道你正在寻找一个没有使用异常处理的答案,但我相信在这种情况下使用EOFException
确定所有输入的读取时间是正确的。
EOFException的JavaDoc声明
此异常主要由数据输入流用于信号流的结束。请注意,许多其他输入操作在流末尾返回特殊值而不是抛出异常。
因此,有些输入流使用其他方式发出文件结束信号,但ObjectInputStream#readObject
使用ObjectInputStream$BlockDataInputStream#peekByte
确定是否有更多数据要读取,peekByte
会抛出到达流末尾时EOFException
。
因此,可以将此异常用作指示已到达文件末尾的指示符。
要在不中断程序流的情况下处理异常,应在层次结构中传递一些可能的异常。它们可以由调用try - catch
的代码中的readContact()
块处理。
EOFException
可以简单地用作我们读完对象的指标。
public TreeMap<String, Contact> readContact() throws FileNotFoundException,
IOException, ClassNotFoundException {
TreeMap<String, Contact> contactMap = new TreeMap<String, Contact>();
// The following call can throw a FileNotFoundException or an IOException.
// Since this is probably better dealt with in the calling function,
// readContact is made to throw these exceptions instead.
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(
new FileInputStream(file)));
while (true) {
try {
// Read the next object from the stream. If there is none, the
// EOFException will be thrown.
// This call might also throw a ClassNotFoundException, which can be passed
// up or handled here.
Contact c = (Contact) in.readObject();
contactMap.put(c.getLastName(), c);
for (Map.Entry<String, Contact> contact : contactMap.entrySet()) {
Contact con = contact.getValue();
System.out.println(con.getLastName() + ", "
+ con.getFirstName() + ": " + con.getPhoneNumber()
+ "\t" + con.getEmail());
}
} catch (EOFException e) {
// If there are no more objects to read, return what we have.
return contactMap;
} finally {
// Close the stream.
in.close();
}
}
}
答案 2 :(得分:2)
EOFException
在您的情况下是合理的方法。捕获EOFExcepion
不会终止您的计划。ObjectOutputStream.writeInt
向文件中写入对象的数量,然后使用ObjectInputStream.readInt
读取此数字并知道要读取的对象数null
作为EOF标记。readObject
进行阅读。答案 3 :(得分:2)
- Exceptions
不仅用于在调用方法时出现问题时发出警报,但也用于{{1和Threads
以及其他各种用途。
- 您可以使用IO
表示文件末尾。
- 使用Exception
组合与上述内容一起使用,以保持程序流畅。
答案 4 :(得分:2)
为什么在从文件中读取对象时遇到这么多麻烦,只需将哈希映射保存到文件中,然后从文件中读取一次,然后执行任何操作。
另外我建议使用像Db4o这样的面向对象数据库中的任何一个来快速执行此操作,然后再也不用担心文件结束异常
答案 5 :(得分:0)
您发现了什么
即使文件中有未读字节,您也发现FileInputStream.available()
返回0 !为什么是这样?这可能发生(由于以下几个原因,呈现FileInputStream.available()
不可靠:
FileInputStream.available()
近似可以无阻塞地读取的字节数FileInputStream
某种替代方式
作为依赖EOFException关闭文件的替代方法,您可以使用(非常小的!)二进制文件来跟踪文件中的对象数。 (从您的代码来看,看起来您只是将对象写入文件。)我使用它的方式只是为了
例如,第一次创建序列化文件时,我可以使二进制文件存储1 1
(指定序列化文件中的对象数占用1个字节,该数字为1) 。这样,在255个对象之后(记住,无符号字节最多只能存储2个 8-1 == 255),如果我写另一个对象(对象编号256到256 2-1 == 65535),二进制文件将作为内容2 1 0
,它指定该数字占用2个字节并且是1 * 256 1 + 0 == 256.假设序列化是可靠的(好的)确保:http://www.ibm.com/developerworks/library/j-serialtest/index.html),这个方法可以让你存储(和检测)多达256个 255-1个字节(这几乎意味着这个方法可以无限期地工作)。
代码本身
如何实现这样的事情将是:
ObjectOutputStream yourOutputStream = new ObjectOutputStream(new FileOutputStream(workingDirectory + File.separatorChar + yourFileName); //The outputStream
File binaryFile = new File(workingDirectory + File.separatorChar + nameOfFile); //the binary file
int numOfObjects = 0, numOfBytes; //The number of Objects in the file
//reading the number of Objects from the file (if the file exists)
try
{
FileInputStream byteReader = new FileInputStream(binaryFile);
numOfBytes = byteReader.read();
//Read the rest of the bytes (the number itself)
for (int exponent = numOfBytes; exponent >= 0; exponent--)
{
numOfObjects += byteReader.read() * Math.pow(256,exponent);
}
}
catch (IOException exception)
{
//if an exception was thrown due to the file not existing
if (exception.getClass() == FileNotFoundException.class)
{
//we simply create the file (as mentioned earlier in this answer)
try
{
FileOutputStream fileCreator = new FileOutputStream(binaryFile);
//we write the integers '1','1' to the file
for (int x = 0; x < 2; x++) fileCreator.write(1);
//attempt to close the file
fileCreator.close();
}
catch (IOException innerException)
{
//here, we need to handle this; something went wrong
innerException.printStackTrace();
System.exit(-1);
}
}
else
{
exception.printStackTrace();
System.exit(-2);
}
}
现在,我们有文件中的对象数量(我留给你了解如何更新字节以指示在yourOutputStream
调用writeObject(yourObject);
时已经写入了一个对象;我得进去。)
编辑:yourOutputStream
要么写入binaryFile
中的所有数据,要么将数据附加到其中。我刚刚发现RandomAccessFile
是一种将数据插入文件中任何位置的方法。我再次向您详细说明。但是你想要这样做。
答案 6 :(得分:-1)
您可以将最后一个对象写为null。 然后迭代直到你在阅读方面得到一个空值。 e.g。
while ((object = inputStream.readObject()) != null) {
// ...
}