第7章 输入/输出
本章目录
7.1 输入/输出、流和相关类
7.2 数据的输入/输出
7.3 文件的输入和输出
7.1 输入/输出、流和相关类
一、流的概念
流是一个想象中的无限长的数据序列。流是Java语言输入/输出的方式,Java语言程序通过流来完成输入/输出工作。流有两种类型:输入流和输出流。在java.io包中,定义了输入
流和输出流的类,分别以不同形式完成输入/输出工作。
二、java.io包中的输入/输出类
java.lang.Object
└─InputStream
├─ByteArrayInputStream
├─FileInputStream
├─FilterInputStream
│ ├─BufferedInputStream
│ ├─DataInputStream
│ ├─LineNumberInputStream
│ └─PushbackInputStream
├─ObjectInputStream
├─PipedInputStream
├─SequenceInputStream
└─StringBufferInputStream
java.lang.Object
└─OutputStream
├─ByteArrayOutputStream
├─FileOutputStream
├─FilterOutputStream
│ ├─BufferedOutputStream
│ ├─DataOutputStream
│ └─PrintStream
├─ObjectOutputStream
└─PipedOutputStream
java.lang.Object
├─File
└─Reader
├─BufferedReader
│ └─LineNumberReader
├─CharArreyReader
├─FilterReader
│ └─PushbackReader
├─InputStreamReader
│ └─FileReader
├─PipedReader
└─StringReader
java.lang.Object
├─RandomAccessFile
└─Writer
├─BufferedWriter
├─CharArreyWriter
├─FilterWriter
├─OutputStreamWriter
│ └─FileWriter
├─PipedWriter
├─PrintWriter
└─StringWriter
管道(pipe):PipedInputStream类和PipedOutputStream类
过滤:FilterInputStream类和FilterOutputStream类
打印流:PrintStream类
缓冲存储:BufferedInputStream类和BufferedOutputStream类
连续输入:SequenceInputStream类
三、输入/输出流常用方法
⒈输入流常用方法
在InputStream中声明了如下9个方法成员,是经常要使用到的方法。
int read() //读下一字节,返回0~255之间的一个整数
int read(byte[] b) //读取最多b.length个字节写入字节数组
int read(byte[] b , int off , int len) //读取最多len个字节写入字节数组,off为起始偏移量
close() //关闭输入流
int available() //检测无阻塞情况下可以从这个输入流中读取的字节数
long skip(long n) //跳过并放弃输入流中的n字节数据并返回n
boolean markSupported() //测定是否支持标记
mark(int readlimit) //标记输入流的当前位置,随后用reset()方法把流重置于标记处
reset() //将流的当前位置重置于mark()方法置标记处
⒉输出流常用方法
在OutputStream中声明了如下5个方法成员,是经常要使用到的方法。
write(int b) //写指定字节到输出流,内容为b的低8位
write(byte[] b) //从数组b写b.length个字节到输出流
write(byte[] b , int off , int len) //从数组b起始偏移量off处写len个字节到输出流
close() //关闭输出流
flush() //清空输出流
7.2 数据的输入/输出
一、标准输入/输出
在java.lang包中的System类中定义了三个与设备关联的对象:InputStream类的对象实例in作为标准输入流对象,对应于键盘输入;PrintStream类的对象实例out作为标准输出流
对象,对应于显示器输出;PrintStream类的对象实例err作为标准错误输出流对象,对应于显示器输出。
二、基于字节的输入和输出
基于字节的输入和输出是Java语言输入/输出流的基本形式,也是计算机数据存储和传输的常用形式。在InputStream类和OutputStream类中定义的输入/输出方法都是基于字节的数
据操作方法。是程序中最为简便的输入/输出方式,但也是最不能保留数据的原有格式的输入/输出方式。
三、基于字符的输入和输出
处理Unicode字符的两个抽象类Reader和Writer,通过在其基础上定义的子类实现 。是Java语言中特别常用的输入/输出方式。
Reader类和Writer类中所声明的方法都是基于字符的输入和输出的基本方法。
字符流与字节流的相互转换问题是必须要解决的问题。
InputStreamReader类用于读取字节数据并转换为指定字符编码的字符,OutputStreamWriter类用于转换指定字符编码的字符为字节数据并写入输出流。
FileReader类和FileWriter类则假定文件的格式已经是字符编码的,从而实现文件的字符输入/输出功能。特别要指出的是这两个类在处理汉字文件的时候很有用。
BufferedReader类和BufferedWriter类是带缓冲区的读写字符流。
CharArrayReader类和CharArrayWriter类分别从字符数组中读写字符。
PipedReader类和PipedWriter类则实现了管道字符流,用于在线程间传递信息。StringReader类和StringWriter类分别从字符串读写字符。
FilterReader类和FilterWriter类分别用于读写已过滤的字符流。
PrintWriter类实现了字符流的打印。
四、基本数据类型的输入和输出
DataInput接口和DataOutput接口描述了从输入流中读取基本类型和向输出流中写入基本类型的方法,DataInputStream类和DataOutputStream类分别实现了DataInput接口和
DataOutput接口。
这两个类由于分别派生自FilterInputStream类和FilterOutputStream类,亦具有过滤流的功能。
五、对象的输入和输出
ObjectInput接口和ObjectOutput接口中分别声明了readObject()方法和writeObject()方法,能够从输入/输出流中读/写Object。
ObjectInputStream类实现了ObjectInput接口和DataInput接口,能够从输入流中读取对象型数据和基本数据类型数据。ObjectOutputStream类实现了ObjectOutput接口和
DataOutput接口,能够向输出流中写入对象型数据和基本数据类型数据。
六、字节数组的输入和输出
ByteArrayInputStream类和ByteArrayOutputStream类中包含有一个内部缓冲区,用来从流中读取或向流中写入字节数组,内部缓冲区用来缓存读写的字节形式的数据,缓冲区的大
小可以随字节数据的多少而调节。在这两个类中重写了InputStream类和OutputStream类中的方法成员。
7.3 文件的输入和输出
文件是具有符号名而且在逻辑上具有完整意义的信息。
文件是操作系统对计算机外部存储设备上所存储的数据进行有效管理的基本单位。
Java语言将每个文件视为顺序字节流。
按照文件的访问方式,文件分为顺序文件和随机访问文件。
一、顺序文件的输入和输出
文件File类的对象实例表示文件系统中的文件路径名和文件名。
该类的构造方法:
File(File parent, String child)
File(String pathname)
File(String parent, String child)
File(URI uri)
主要的方法成员有:
String getName() //获取文件名
String getPath() //获取文件路径
String getAbsolutePath() //获取文件的绝对路径
String getParent() //获取由当前对象所表示文件的父目录
boolean renameTo(File newName) //更改文件名为参数所指定的文件名
boolean exists() //检测本文件是否存在
boolean canWrite() //检测文件是否可写
boolean canRead() //检测文件是否可读
boolean isFile() //检测对象是否代表一个文件
boolean isDirectory() //检测对象是否代表一个目录
boolean isAbsolute() //检测对象是否代表一个绝对路径
long lastModified() //检测文件最后一次被修改的时间
long length() //检测文件长度
boolean delete() //删除文件
boolean mkdir() //创建目录
String[] list() //列出当前目录中的文件
经常使用BufferedReader类和BufferedWriter类来完成文件的读写功能,使用StringBuffer类来进行字符串读入时的缓冲存储。
对于汉字内容的文件,通常使用FileReader类和FileWriter类来完成读写。
经常使用的一种“包装流对象技术”,把一种流的服务添加到另一种流中。
二、随机访问文件的输入和输出
随机访问文件类RandomAccessFile代表一个可以随机访问的文件,以避免对一般文件操作时从文件开始处顺序读写文件,可以针对现存文件建立随机访问文件。RandomAccessFile
对象具有FileInputStream、FileOutputStream、DataInputStream和DataOutputStream的所有功能,其中定义有文件指针,并可以分别对各种基本数据类型的数据进行专门的读写
操作。 构造方法为:
public RandomAccessFile(File file , String mode)
public RandomAccessFile(String name , String mode)
file代表File对象,name代表文件名,mode取“r”或“rw”代表“只读”或“读写”,意味着创建的随机访问文件可以是只读的,也可以是可读写的。新创建的随机访问文件对象
实例的文件指针是指向文件的开始位置的,当进行文件的读写操作时,文件指针将隐式地按照所读写的内容的字节数自动调节位置。
主要方法成员
public long getFilePointer() //返回文件的当前偏移量
public long length() //返回文件的长度
public void seek(long pos) //设置相对于文件头的文件指针偏移量
除了这几个方法之外,RandomAccessFile类中实现了DataInput接口和DataOutput接口,所以该类也拥有读写基本数据类型的方法成员,能够完成基本数据类型的读写操作。
操作随机访问文件要注意正确移动文件指针,关键在于使用seek()方法移动文件指针,注意不要超出文件的结尾,否则将导致一个EOFException。
对一个已经存在的随机访问文件进行写操作时将会用新内容覆盖文件中同一位置上已有的内容,而不是将新内容添加到文件中,只有当文件指针是指向文件末尾的时候才会将新内
容添加到文件末尾。
//Example 1 of Chapter 7
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class StreamDemo1 extends JFrame
{
private ScrollPane scrollPane;
private JTextArea area;
private JButton openbutton, savebutton, writebutton;
private JPanel panel;
private BufferedReader input;
private BufferedWriter output;
private StringBuffer buffer;
public StreamDemo1()
{
super( "文件输入/输出演示" );
getContentPane().setLayout( new BorderLayout() );
scrollPane = new ScrollPane();
area = new JTextArea();
openbutton = new JButton( "打开文件" );
savebutton = new JButton( "保存文件" );
savebutton.setEnabled( false );
writebutton = new JButton( "展示文件内容" );
writebutton.setEnabled( false );
panel = new JPanel();
panel.setLayout( new FlowLayout() );
openbutton.addActionListener
(
new ActionListener()
{
public void actionPerformed( ActionEvent event )
{
openFile();
}
}
);
savebutton.addActionListener
(
new ActionListener()
{
public void actionPerformed( ActionEvent event )
{
saveFile();
}
}
);
writebutton.addActionListener
(
new ActionListener()
{
public void actionPerformed( ActionEvent event )
{
displayFileContent();
}
}
);
scrollPane.add( area );
panel.add( openbutton );
panel.add( savebutton );
panel.add( writebutton );
getContentPane().add( scrollPane, BorderLayout.CENTER );
getContentPane().add( panel, BorderLayout.NORTH );
setSize( 350, 200 );
setVisible( true );
}
private void openFile()
{
JFileChooser open = new JFileChooser( new File( "d://" ) );
open.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = open.showOpenDialog( this );
if( result == JFileChooser.CANCEL_OPTION )
return;
File inputfilename = open.getSelectedFile();
if( inputfilename == null || inputfilename.getName().equals( "" ))
{
JOptionPane.showMessageDialog( this, "没有正确选择文件", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
else
{
try{
if( input == null )input = new BufferedReader( new FileReader( inputfilename ) );
}
catch( IOException ioe)
{
JOptionPane.showMessageDialog( this, "打开文件出错", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
savebutton.setEnabled( true );
}
}
private void saveFile()
{
JFileChooser save = new JFileChooser( new File( "d://" ) );
save.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = save.showSaveDialog( this );
if( result == JFileChooser.CANCEL_OPTION )
return;
File outputfilename = save.getSelectedFile();
if( outputfilename == null || outputfilename.getName().equals( "" ))
{
JOptionPane.showMessageDialog( this, "没有正确选择文件", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
else
{
try{
if( output == null )output = new BufferedWriter( new FileWriter( outputfilename ) );
buffer = new StringBuffer();
String text;
while( (text = input.readLine())!=null )
{
output.write( text );
output.newLine();
buffer.append( text+"/n" );
}
output.flush();
input.close();
output.close();
input = null;
output = null;
}
catch( IOException ioe)
{
JOptionPane.showMessageDialog( this, "打开文件出错", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
writebutton.setEnabled( true );
}
}
private void displayFileContent()
{
area.setText( buffer.toString() );
}
public static void main(String[] args)
{
StreamDemo1 demo = new StreamDemo1();
demo.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
}
//Example 2 of Chapter 7
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class StreamDemo2 extends JFrame
{
private ScrollPane scrollPane;
private JTextArea area;
private JButton newbutton, ranreadbutton, ranwritebutton, readbutton;
private JPanel panel;
private RandomAccessFile input, output;
private int a[] = {1, 2, 3, 4, 5, 6, 7, 8}, aa1 = 2, aa2 = 3;
private String s[] = {"数学","物理","化学","语文","英语","政治","生物","体育"};
private String ss1 = "地理", ss2 = "历史";
private String n[] = {"必修","必修","必修","必修","必修","选修","选修","必修"};
private String nn1 = "必修", nn2 = "必修";
private static final int SIZE = 12;
public StreamDemo2()
{
super( "随机文件输入/输出演示" );
getContentPane().setLayout( new BorderLayout() );
scrollPane = new ScrollPane();
area = new JTextArea();
newbutton = new JButton( "建新文件" );
ranreadbutton = new JButton( "随机读文件" );
ranwritebutton = new JButton( "随机写文件" );
readbutton = new JButton( "展示文件内容" );
panel = new JPanel();
panel.setLayout( new FlowLayout() );
newbutton.addActionListener
(
new ActionListener()
{
public void actionPerformed( ActionEvent event )
{
newFile();
}
}
);
ranreadbutton.addActionListener
(
new ActionListener()
{
public void actionPerformed( ActionEvent event )
{
randomReadFile();
}
}
);
ranwritebutton.addActionListener
(
new ActionListener()
{
public void actionPerformed( ActionEvent event )
{
randomWriteFile();
}
}
);
readbutton.addActionListener
(
new ActionListener()
{
public void actionPerformed( ActionEvent event )
{
readFile();
}
}
);
scrollPane.add( area );
panel.add( newbutton );
panel.add( ranreadbutton );
panel.add( ranwritebutton );
panel.add( readbutton );
getContentPane().add( scrollPane, BorderLayout.CENTER );
getContentPane().add( panel, BorderLayout.NORTH );
setSize( 450, 200 );
setVisible( true );
}
private void newFile()
{
JFileChooser open = new JFileChooser( new File( "d://" ) );
open.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = open.showSaveDialog( this );
if( result == JFileChooser.CANCEL_OPTION )
return;
File filename = open.getSelectedFile();
if( filename == null || filename.getName().equals( "" ))
{
JOptionPane.showMessageDialog( this, "没有正确选择文件", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
else
{
try{
if( output == null )output = new RandomAccessFile( filename, "rw" );
for( int i = 0; i < a.length; i++ )write( output, a[ i ], s[ i ], n[ i ] );
area.setText( "" );
output.close();
output = null;
}
catch( IOException ioe)
{
JOptionPane.showMessageDialog( this, "保存文件出错", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
}
}
private void randomReadFile()
{
JFileChooser open = new JFileChooser( new File( "d://" ) );
open.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = open.showOpenDialog( this );
if( result == JFileChooser.CANCEL_OPTION )
return;
File filename = open.getSelectedFile();
if( filename == null || filename.getName().equals( "" ))
{
JOptionPane.showMessageDialog( this, "没有正确选择文件", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
else
{
try{
if( input == null )input = new RandomAccessFile( filename, "r" );
input.seek( (5-1)*SIZE );
area.setText( read( input ) );
input.close();
input = null;
}
catch( IOException ioe)
{
JOptionPane.showMessageDialog( this, "打开文件出错", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
}
}
private void randomWriteFile()
{
JFileChooser open = new JFileChooser( new File( "d://" ) );
open.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = open.showSaveDialog( this );
if( result == JFileChooser.CANCEL_OPTION )
return;
File filename = open.getSelectedFile();
if( filename == null || filename.getName().equals( "" ))
{
JOptionPane.showMessageDialog( this, "没有正确选择文件", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
else
{
try{
if( output == null )output = new RandomAccessFile( filename, "rw" );
output.seek( (aa1-1)*SIZE );
write( output, aa1, ss1, nn1 );
output.seek( (aa2-1)*SIZE );
write( output, aa2, ss2, nn2 );
area.setText( "" );
output.close();
output = null;
}
catch( IOException ioe)
{
JOptionPane.showMessageDialog( this, "保存文件出错", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
}
}
private void readFile()
{
JFileChooser open = new JFileChooser( new File( "d://" ) );
open.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = open.showOpenDialog( this );
if( result == JFileChooser.CANCEL_OPTION )
return;
File filename = open.getSelectedFile();
if( filename == null || filename.getName().equals( "" ))
{
JOptionPane.showMessageDialog( this, "没有正确选择文件", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
else
{
try{
if( input == null )input = new RandomAccessFile( filename, "r" );
area.setText( "" );
while( input.getFilePointer() < input.length() )
{
area.append( read( input )+"/n" );
}
input.close();
input = null;
}
catch( IOException ioe)
{
JOptionPane.showMessageDialog( this, "打开文件出错", "错误提示",
JOptionPane.ERROR_MESSAGE );
}
}
}
private String read( RandomAccessFile file ) throws IOException
{
return ""+file.readInt()+file.readChar()+file.readChar()
+file.readChar()+file.readChar();
}
private void write( RandomAccessFile file, int i, String s1, String s2)
throws IOException
{
file.writeInt( i );
file.writeChars( s1 );
file.writeChars( s2 );
}
public static void main(String[] args)
{
StreamDemo2 demo = new StreamDemo2();
demo.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
}