第八章输入输出流
【课前思考】
1.字节流和字符流的基类各是什么?
2.什么是对象的串行化?对象串行化的作用是什么?
【学习目标】
本讲主要讲述了java语言中的输入/输出的处理,通过本讲的学习,同学们可以编写更为完善的java 程序。
【学习指南】
仔细阅读本章各知识点的内容, 深刻理解 java 语言中输入/输出流的处理方法,掌握处理问题的方法,多练习,多上机。
【难重点】
●遇到实际问题时,要根据需要正确使用各种输入/输出流,特别是对中文使用适当的字符输入流。
●正确使用对象串行化的方法。
●处理字符流时,其构造方法的参数是一个字节流。
●对象串行化的概念。
【知识点】
●I/O 流概述
●文件处理
●过滤流
●字符流的处理
●对象的串行化
●其它常用的流
【内容】
第一节数据流的基本概念
理解数据流
流一般分为输入流(Input Stream)和输出流(Output Stream)两类,但这种划分并不是绝对的。比如一个文件,当向其中写数据时,它就是一个输出流;当从其中读取数据时,它就是一个输入流。当然,键盘只是一个数人流,而屏幕则只是一个输出流。
Java的标准数据流
标准输入输出指在字符方式下(如DOS),程序与系统进行交互的方式,分为三种:
标准输入studin,对象是键盘。
标准输出stdout,对象是屏幕。
标准错误输出stderr,对象也是屏幕。
例 8.1 从键盘输入字符。
本例用System.in.read(buffer)从键盘输入一行字符,存储在缓冲区buffer中,count保存实际读入的字节个数,再以整数和字符两种方式输出buffer中的值。Read方法在java.io包中,而且要抛出IOException异常。程序如下:
import java.io.*;
public class Input1
{
public static void main(String args[]) throws IOException
{
System.out.println("Input: ");
byte buffer[] = new byte[512]; //输入缓冲区
int count = System.in.read(buffer); //读取标准输入流
System.out.println("Output: ");
for (int i=0;i { System.out.print(" "+buffer[i]); } System.out.println(); for (int i=0;i { System.out.print((char) buffer[i]); } System.out.println("count = "+ count); //buffer实际长度 } } 程序中,main方法采用throws子句抛出IOException异常交由系统处理。 Java.io包中的数据流及文件类 字节流: 从InputStream和OutputStream派生出来的一系列类。这类流以字节(byte)为基本处理单位。 ●InputStream、OutputStream ●◇ FileInputStream、FileOutputStream ●◇ PipedInputStream、PipedOutputStream ●◇ ByteArrayInputStream、ByteArrayOutputStream ●◇ FilterInputStream、FilterOutputStream ●◇ DataInputStream、DataOutputStream ●◇ BufferedInputStream、BufferedOutputStream 字符流: 从Reader和Writer派生出的一系列类,这类流以16位的Unicode码表示的字符为基本处理单位 Reader、Writer ◇ InputStreamReader、OutputStreamWriter ◇ FileReader、FileWriter ◇ CharArrayReader、CharArrayWriter ◇ PipedReader、PipedWriter ◇ FilterReader、FilterWriter ◇ BufferedReader、BufferedWriter ◇ StringReader、StringWriter 第二节字节流初步 InputStream 和OutputStream ●read():从流中读入数据 ●skip():跳过流中若干字节数 ●available():返回流中可用字节数 ●mark():在流中标记一个位置 ●reset():返回标记过得位置 ●markSupport():是否支持标记和复位操作 ●close():关闭流 ●int read() 从输入流中读一个字节,形成一个0~255之间的整数返回(是一个抽象方法)。 ●int read(byte b[]) 读多个字节到数组中。 ●int read(byte b[], int off, int len) ●write(int b) 将一个整数输出到流中(只输出低位字节,抽象) ●write(byte b[]) 将字节数组中的数据输出到流中 ●write(byte b[], int off, int len) 将数组b中从off指定的位置开始,长度为len的数据输出到流中 ●flush():刷空输出流,并将缓冲区中的数据强制送出 ●close():关闭流 从输入流中读取长度为len的数据,写入数组b中从索引off开始的位置,并返回读取得字节数。 进行I/O操作时可能会产生I/O例外,属于非运行时例外,应该在程序中处理。如:型 FileNotFoundException, EOFException, IOException 例 8.2 打开文件。 本例以FileInputStream的read(buffer)方法,每次从源程序文件OpenFile.java中读取512个字节,存储在缓冲区buffer中,再将以buffer中的值构造的字符串new String(buffer)显示在屏幕上。程序如下: import java.io.*; public class OpenFile { public static void main(String args[]) throws IOException { try { //创建文件输入流对象 FileInputStream rf = new FileInputStream("OpenFile.java"); int n=512; byte buffer[] = new byte[n]; while ((rf.read(buffer,0,n)!=-1) && (n>0)) //读取输入流 { System.out.print(new String(buffer)); } System.out.println(); rf.close(); //关闭输入流 } catch (IOException ioe) { System.out.println(ioe); } catch (Exception e) { System.out.println(e); } } } 例 8.3 写入文件。 本例用System.in.read(buffer)从键盘输入一行字符,存储在缓冲区buffer中,再以FileOutStream的write(buffer)方法,将buffer中内容写入文件Write1.txt中,程序如下: import java.io.*; public class Write1 { public static void main(String args[]) { try { System.out.print("Input: "); int count,n=512; byte buffer[] = new byte[n]; count = System.in.read(buffer); //读取标准输入流 FileOutputStream wf = new FileOutputStream("Write1.txt"); //创建文件输出流对象 wf.write(buffer,0,count); //写入输出流 wf.close(); //关闭输出流 System.out.println("Save to Write1.txt!"); } catch (IOException ioe) { System.out.println(ioe); } catch (Exception e) { System.out.println(e); } } } 第三节文件操作 File类 File类声明如下: public class File ectends Object implements Serializable,Comparable 构造方法: public File(String pathname) public File(File patent,String chile) public File(String patent,String child) 文件名的处理 String getName( ); //得到一个文件的名称(不包括路径) String getPath( ); //得到一个文件的路径名 String getAbsolutePath( );//得到一个文件的绝对路径名 String getParent( ); //得到一个文件的上一级目录名 String renameTo(File newName); //将当前文件名更名为给定文件的完整路径文件属性测试 boolean exists( ); //测试当前File对象所指示的文件是否存在 boolean canWrite( );//测试当前文件是否可写 boolean canRead( );//测试当前文件是否可读 boolean isFile( ); //测试当前文件是否是文件(不是目录) boolean isDirectory( ); //测试当前文件是否是目录 普通文件信息和工具 long lastModified( );//得到文件最近一次修改的时间 long length( ); //得到文件的长度,以字节为单位 boolean delete( ); //删除当前文件 目录操作 boolean mkdir( ); //根据当前对象生成一个由该对象指定的路径 String list( ); //列出当前目录下的文件 例 8.4 自动更新文件。 本例使用File类对象对指定文件进行自动更新的操作。程序如下: import java.io.*; import java.util.Date; import java.text.SimpleDateFormat; public class UpdateFile { public static void main(String args[]) throws IOException { String fname = "Write1.txt"; //待复制的文件名 String childdir = "backup"; //子目录名 new UpdateFile().update(fname,childdir); } public void update(String fname,String childdir) throws IOException { File f1,f2,child; f1 = new File(fname); //当前目录中创建文件对象f1 child = new File(childdir); //当前目录中创建文件对象child if (f1.exists()) { if (!child.exists()) //child不存在时创建子目录 child.mkdir(); f2 = new File(child,fname); //在子目录child中创建文件f2 if (!f2.exists() || //f2不存在时或存在但日期较早时 f2.exists()&&(https://www.wendangku.net/doc/1518221120.html,stModified() > https://www.wendangku.net/doc/1518221120.html,stModified())) copy(f1,f2); //复制 getinfo(f1); getinfo(child); } else System.out.println(f1.getName()+" file not found!"); } public void copy(File f1,File f2) throws IOException { //创建文件输入流对象 FileInputStream rf = new FileInputStream(f1); FileOutputStream wf = new FileOutputStream(f2); //创建文件输出流对象 int count,n=512; byte buffer[] = new byte[n]; count = rf.read(buffer,0,n); //读取输入流 while (count != -1) { wf.write(buffer,0,count); //写入输出流 count = rf.read(buffer,0,n); } System.out.println("CopyFile "+f2.getName()+" !"); rf.close(); //关闭输入流 wf.close(); //关闭输出流 } public static void getinfo(File f1) throws IOException { SimpleDateFormat sdf; sdf= new SimpleDateFormat("yyyy年MM月dd日hh时mm分"); if (f1.isFile()) System.out.println(" f1.length()+"\t"+sdf.format(new Date(https://www.wendangku.net/doc/1518221120.html,stModified()))); else { System.out.println(" File[] files = f1.listFiles(); for (int i=0;i getinfo(files[i]); } } } https://www.wendangku.net/doc/1518221120.html,stModified()返回一个表示日期的长整型,值为从1970年1月1日零时开始计算的毫秒数,并以此长整型构造一个日期对象,再按指定格式输出日期。程序运行结果如下: 文件过滤器 类FilterInputStream和FilterOutputStream分别对其他输入/输出流进行特殊处理,它们在读/写数据的同时可以对数据进行特殊处理。另外还提供了同步机制,使得某一时刻只有一个线程可以访问一个输入/输出流 类FilterInputStream和FilterOutputStream分别重写了父类InputStream和OutputStream的所有方法,同时,它们的子类也应该重写它们的方法以满足特定的需要 ?要使用过滤流,首先必须把它连接到某个输入/输出流上,通常在构造方法的参数中指定所要连接的流: –FilterInputStream(InputStream in); –FilterOutputStream(OutputStream out); 这两个类是抽象类,构造方法也是保护方法 类BufferedInputStream和BufferedOutputStream实现了带缓冲的过滤流,它提供了缓冲机制,把任意的I/O流“捆绑”到缓冲流上,可以提高读写效率 ?在初始化时,除了要指定所连接的I/O流之外,还可以指定缓冲区的大小。缺省大小的缓冲区适合于通常的情形;最优的缓冲区大小常依赖于主机操作系统、可使用的内存空间以及机器的配置等;一般缓冲区的大小为内存页或磁盘块等地整数倍,如8912字节或更小。 –BufferedInputStream(InputStream in[, int size]) –BufferedOutputStream(OutputStream out[, int size]) 例 8.5 列出当前目录中带过滤器的文件名清单。 本例实现FilenameFilter接口中的accept方法,在当前目录中列出带过滤器的文件名。 程序如下: import java.io.*; public class DirFilter implements FilenameFilter { private String prefix="",suffix=""; //文件名的前缀、后缀 public DirFilter(String filterstr) { filterstr = filterstr.toLowerCase(); int i = filterstr.indexOf('*'); int j = filterstr.indexOf('.'); if (i>0) prefix = filterstr.substring(0,i); if (j>0) suffix = filterstr.substring(j+1); } public static void main(String args[]) { //创建带通配符的文件名过滤器对象 FilenameFilter filter = new DirFilter("w*abc.txt"); File f1 = new File(""); File curdir = new File(f1.getAbsolutePath(),""); //当前目录 System.out.println(curdir.getAbsolutePath()); String[] str = curdir.list(filter); //列出带过滤器的文件名清单 for (int i=0;i System.out.println("\t"+str[i]); } public boolean accept(File dir, String filename) { boolean yes = true; try { filename = filename.toLowerCase(); yes = (filename.startsWith(prefix)) & (filename.endsWith(suffix)); } catch(NullPointerException e) { } return yes; } } 程序运行时,列出当前目录中符合过滤条件“w*.txt“的文件名清单。结果如下: D:\myjava Write1.txt Write2.txt 文件对话框 随机文件操作 于InputStream 和OutputStream 来说,它们的实例都是顺序访问流,也就是说,只能对文件进行顺序地读/写。随机访问文件则允许对文件内容进行随机读/写。在java中,类RandomAccessFile 提供了随机访问文件的方法。类RandomAccessFile的声明为: public class RandomAccessFile extends Object implements DataInput, DataOutput File:以文件路径名的形式代表一个文件 FileDescriptor:代表一个打开文件的文件描述 FileFilter & FilenameFilter:用于列出满足条件的文件 File.list(FilenameFilter fnf) File.listFiles(FileFilter ff) FileDialog.setFilenameFilter(FilenameFilter fnf) ?FileInputStream & FileReader:顺序读文件 ?FileOutputStream & FileWriter:顺序写文件 ?RandomAccessFile:提供对文件的随机访问支持 类RandomAccessFile则允许对文件内容同时完成读和写操作,它直接继承Object,并且同时实现了接口DataInput和DataOutput,提供了支持随机文件操作的方法 DataInput和DataOutput中的方法 ?readInt(), writeDouble()… int skipBytes(int n):将指针乡下移动若干字节 length():返回文件长度 long getFilePointer():返回指针当前位置 void seek(long pos):将指针调到所需位置 void setLength(long newLength):设定文件长度 构造方法: RandomAccessFile(File file, String mode) RandomAccessFile(String name, String mode) mode 的取值 –“r” 只读. 任何写操作都将抛出IOException。 –“rw” 读写. 文件不存在时会创建该文件,文件存在时,原文件内容不变,通过写操作改变文件内容。 –“rws” 同步读写. 等同于读写,但是任何协操作的内容都被直接写入物理文件,包括文件内容和文件属性。 –“rwd” 数据同步读写. 等同于读写,但任何内容写操作都直接写到物理文件,对文件属性内容的修改不是这样。 例 8.6 随机文件操作。 本例对一个二进制整数文件实现访问操作当以可读写方式“rw“打开一个文件”prinmes.bin“时,如果文件不存在,将创建一个新文件。先将2作为最小素数写入文件,再依次测试100以内的奇数,将每次产生一个素数写入文件尾。 程序如下: import java.io.*; public class PrimesFile { RandomAccessFile raf; public static void main(String args[]) throws IOException { (new PrimesFile()). createprime(100); } public void createprime(int max) throws IOException { raf=new RandomAccessFile("primes.bin","rw");//创建文件对象 raf.seek(0); //文件指针为0 raf.writeInt(2); //写入整型 int k=3; while (k<=max) { if (isPrime(k)) raf.writeInt(k); k = k+2; } output(max); raf.close(); //关闭文件 } public boolean isPrime(int k) throws IOException { int i=0,j; boolean yes = true; try { raf.seek(0); int count = (int)(raf.length()/4); //返回文件字节长度 while ((i<=count) && yes) { if (k % raf.readInt()==0) //读取整型 yes = false; else i++; raf.seek(i*4); //移动文件指针 } } catch(EOFException e) { } //捕获到达文件尾异常 return yes; } public void output(int max) throws IOException { try { raf.seek(0); System.out.println("[2.."+max+"]中有 "+ (raf.length()/4)+" 个素数:"); for (int i=0;i<(int)(raf.length()/4);i++) { raf.seek(i*4); System.out.print(raf.readInt()+" "); if ((i+1)%10==0) System.out.println(); } } catch(EOFException e) { } System.out.println(); } } 程序运行时创建文件“primes.bin“,并将素数写入其中,结果如下: [2..100]中有 25 个素数: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 第四节字符流 Reader类和Writer类 前面说过,在JDK1.1之前,java.io包中的流只有普通的字节流(以byte为基本处理单位的流),这种流对于以16位的Unicode码表示的字符流处理很不方便。从JDK1.1开始, java.io包中加入了专门用于字符流处理的类,它们是以Reader和Writer为基础派生的一系列类 同类InputStream和OutputStream一样,Reader和Writer也是抽象类,只提供了一系列用于字符流处理的接口。它们的方法与类InputStream和OutputStream类似,只不过其中的参数换成字符或字符数组Reader类 ?void close() ?void mark(int readAheadLimit) ?boolean markSupported() : ?int read() ?int read(char[] cbuf) ?int read(char[] cbuf, int off, int len) ?boolean ready() ?void reset() ?long skip(long n) Writer类 ?void close() ?void flush() ?void write(char[] cbuf) ?void write(char[] cbuf, int off, int len) ?void write(int c) ?void write(String str) ?void write(String str, int off, int len) 例 8.7 文件编辑器。 本例实现文件编辑器中的打开、保存文件功能。程序如下: import java.awt.*; import java.awt.event.*; import java.io.*; public class EditFile1 extends WindowAdapter implements ActionListener,TextListener { Frame f; TextArea ta1; Panel p1; TextField tf1; Button b1,b2,b3; FileDialog fd; File file1 = null; public static void main(String args[]) { (new EditFile1()).display(); } public void display() { f = new Frame("EditFile"); f.setSize(680,400); f.setLocation(200,140); f.setBackground(Color.lightGray); f.addWindowListener(this); tf1 = new TextField(); tf1.setEnabled(false); tf1.setFont(new Font("Dialog",0,20)); //设置文本行的初始字体 f.add(tf1,"North"); ta1 = new TextArea(); ta1.setFont(new Font("Dialog",0,20)); //设置文本区的初始字体 f.add(ta1); ta1.addTextListener(this); //注册文本区的事件监听程序 p1 = new Panel(); p1.setLayout(new FlowLayout(FlowLayout.LEFT)); b1 = new Button("Open"); b2 = new Button("Save"); b3 = new Button("Save As"); p1.add(b1); p1.add(b2); p1.add(b3); b2.setEnabled(false); b3.setEnabled(false); b1.addActionListener(this); //注册按钮的事件监听程序 b2.addActionListener(this); b3.addActionListener(this); f.add(p1,"South"); f.setVisible(true); } public void textValueChanged(TextEvent e) { //实现TextListener接口中的方法,对文本区操作时触发 b2.setEnabled(true); b3.setEnabled(true); } public void actionPerformed(ActionEvent e) { if (e.getSource()==b1) //单击[打开]按钮时 { fd = new FileDialog(f,"Open",FileDialog.LOAD); fd.setVisible(true); //创建并显示打开文件对话框 if ((fd.getDirectory()!=null) && (fd.getFile()!=null)) { tf1.setText(fd.getDirectory()+fd.getFile()); try //以缓冲区方式读取文件内容 { file1 = new File(fd.getDirectory(),fd.getFile()); FileReader fr = new FileReader(file1); BufferedReader br = new BufferedReader(fr); String aline; while ((aline=br.readLine()) != null)//按行读取文本 ta1.append(aline+"\r\n"); fr.close(); br.close(); } catch (IOException ioe) { System.out.println(ioe); } } } if ((e.getSource()==b2) || (e.getSource()==b3)) { //单击[保存]按钮时 if ((e.getSource()==b3) ||(e.getSource()==b2)&&(file1==null)) { //单击[SaveAs]按钮时,或单击[Save]按钮且文件对象为空时 fd = new FileDialog(f,"Save",FileDialog.SAVE); if (file1==null) fd.setFile("Edit1.txt"); else fd.setFile(file1.getName()); fd.setVisible(true); //创建并显示保存文件对话框 if ((fd.getDirectory()!=null) && (fd.getFile()!=null)) { tf1.setText(fd.getDirectory()+fd.getFile()); file1 = new File(fd.getDirectory(),fd.getFile()); save(file1); } } else save(file1); } } public void save(File file1) { try //将文本区内容写入字符输出流 { FileWriter fw = new FileWriter(file1); fw.write(ta1.getText()); fw.close(); b2.setEnabled(false); b3.setEnabled(false); } catch (IOException ioe) { System.out.println(ioe); } } public void windowClosing(WindowEvent e) { System.exit(0); } } 第五节字节流的高级应用 管道流 管道用来把一个程序、线程和代码块的输出连接到另一个程序、线程和代码块的输入。java.io中提供了类PipedInputStream和PipedOutputStream作为管道的输入/输出流 管道输入流作为一个通信管道的接收端,管道输出流则作为发送端。管道流必须是输入输出并用,即在使用管道前,两者必须进行连接 管道输入/输出流可以用两种方式进行连接: –在构造方法中进行连接 ?PipedInputStream(PipedOutputStream pos); ?PipedOutputStream(PipedInputStream pis); –通过各自的connect()方法连接 ?在类PipedInputStream中,connect(PipedOutputStream pos); ?在类PipedOutputStream中,connect(PipedInputStream pis); 例 8.8 管道流。 本例例管道流的使用方法。设输入管道in与输出管道out已连接,Send线程向输出管道out发送数据,Receive线程从输入管道in中接收数据。程序如下: import java.io.*; public class Pipedstream { public static void main (String args[]) { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(); try { in.connect(out); } catch(IOException ioe) { } Send s1 = new Send(out,1); Send s2 = new Send(out,2); Receive r1 = new Receive(in); Receive r2 = new Receive(in); s1.start(); s2.start(); r2.start(); } } class Send extends Thread //发送线程 { PipedOutputStream out; static int count=0; //记录线程个数 int k=0; public Send(PipedOutputStream out,int k) { this.out= out; this.k= k; this.count++; //线程个数加1 } public void run( ) { System.out.print("\r\nSend"+this.k+": "+this.getName()+" "); int i=k; try { while (i<10) { out.write(i); i+=2; sleep(1); } if (Send.count==1) //只剩一个线程时 { out.close(); //关闭输入管道流 System.out.println(" out closed!"); } else this.count--; //线程个数减1 } catch(InterruptedException e) { } catch(IOException e) { } } } class Receive extends Thread //接收线程 { PipedInputStream in; public Receive(PipedInputStream in) { } public void run( ) { System.out.print("\r\nReceive: "+this.getName()+" "); try { int i = in.read(); while (i!=-1) //输入流未结束时 { System.out.print(i+" "); i = in.read(); sleep(1); } in.close(); //关闭输入管道流 } catch(InterruptedException e) { } catch(IOException e) { System.out.println(e); } } } 程序运行结果如下: Send1: Thread-0 Send2: Thread-1 Receive: Thread-2 1 Receive: Thread-3 2 3 4 5 7 out closed! 6 8 9 java.io.IOException: Pipe closed! 数据流 DataInputStream和DataOutputStream 在提供了字节流的读写手段的同时, 以统一的通用的形式向输入流中写入boolean,int,long,double等基本数据类型, 并可以在次把基本数据类型的值读取回来。 提供了字符串读写的手段。 分别实现了DataInput和DataOutput接口 声明类: Public class DataInputStream extends filterInputStream implements DataInput 例 8.9 数据流。 本例演示数据流的使用方法。 程序如下: import java.io.*; public class Datastream { public static void main(String arg[]) { String fname = "student1.dat"; new Student1("Wang").save(fname); new Student1("Li").save(fname); Student1.display(fname); } } class Student1 { static int count=0; int number=1; String name; Student1(String n1) { this.count++; //编号自动加1 this.number = this.count; https://www.wendangku.net/doc/1518221120.html, = n1; } Student1() { this(""); } void save(String fname) { try { //添加方式创建文件输出流 FileOutputStream fout = new FileOutputStream(fname,true); DataOutputStream dout = new DataOutputStream(fout); dout.writeInt(this.number); dout.writeChars(https://www.wendangku.net/doc/1518221120.html,+"\n"); dout.close(); } catch (IOException ioe){} } static void display(String fname) { try { FileInputStream fin = new FileInputStream(fname); DataInputStream din = new DataInputStream(fin); int i = din.readInt(); while (i!=-1) //输入流未结束时 { System.out.print(i+" "); char ch ; while ((ch=din.readChar())!='\n') //字符串未结束时 System.out.print(ch); System.out.println(); i = din.readInt(); } din.close(); } catch (IOException ioe){} } } 程序运行结果如下: 1 Wang 2 Li 对象流 ?对象的持续性(Persistence) –能够纪录自己的状态一边将来再生的能力,叫对象的持续性 ?对象的串行化(Serialization) –对象通过写出描述自己状态的数值来记录自己的过程叫串行化。串行化的主要任务是 写出对象实例变量的数值,如果变量是另一个对象的引用,则引用的对象也要串行化。 这个过程是递归的 ?对象流 –能够输入输出对象的流称为对象流。 –可以将对象串行化后通过对象输入输出流写入文件或传送到其它地方在java中,允许可串行化的对象在通过对象流进行传输。只有实现Serializable接口的类才能被串行化, Serializable接口中没有任何方法,当一个类声明实现Serializable接口时,只是表明该类加入对象串行化协议 要串行化一个对象,必须与一定的对象输出/输入流联系起来,通过对象输出流将对象状态保存下来(将对象保存到文件中,或者通过网络传送到其他地方) ,再通过对象输入流将对象状态恢复类ObjectOutputStream和ObjectInputStream分别继承了接口ObjectOutput和ObjectInput,将数据流功能扩展到可以读写对象,前者用writeObject()方法可以直接将对象保存到输出流中,而后者用readObject()方法可以直接从输入流中读取一个对象 例 8.10 对象流。 本例声明Student2为序列化的类。Save方法中,创建对象输出流out,并以添加方式向文件中直接写入当前对象out.writeObject(this);display方法中,创建对象输入流in,从文件中直接读取一个对象in.readObject(),获得该对象的类名、接口名等属性,并显示其中的成员变量。程序如下: import java.io.*; public class Student2 implements Serializable //序列化 { int number=1; String name; Student2(int number,String n1) { this.number = number; https://www.wendangku.net/doc/1518221120.html, = n1; } Student2() { this(0,""); } void save(String fname) { try { FileOutputStream fout = new FileOutputStream(fname); ObjectOutputStream out = new ObjectOutputStream(fout); out.writeObject(this); //写入对象 out.close(); } catch (FileNotFoundException fe){} catch (IOException ioe){} } void display(String fname) { try { FileInputStream fin = new FileInputStream(fname); ObjectInputStream in = new ObjectInputStream(fin); Student2 u1 = (Student2)in.readObject(); //读取对象 System.out.println(u1.getClass().getName()+" "+ u1.getClass().getInterfaces()[0]); System.out.println(" "+u1.number+" "+https://www.wendangku.net/doc/1518221120.html,); in.close(); } catch (FileNotFoundException fe){} catch (IOException ioe){} catch (ClassNotFoundException ioe) {} } public static void main(String arg[]) { String fname = "student2.obj"; Student2 s1 = new Student2(1,"Wang"); s1.save(fname); s1.display(fname); } } 程序运行结果如下: Student2 interface java.io.Serializable 1 Wang 山西大学计算机与信息技术学院 实验报告 姓名学号专业班级 课程名称 Java实验实验日期2013-12-4 成绩指导教师批改日期实验名称实验9 Java的输入输出流 ●实验目的 1. 理解I/O流的概念,掌握其分类 2. 掌握文本文件读写、二进制文件读写 ●实验内容 1. 分别使用FileWriter 和BufferedWriter 往文件中写入1万个随机数,比较用时的多少?(用时采用方法System.currentTimeMillis())求时间差; 使用:FileWriter 程序源代码 package a; import java.io.*; public class Filewriter { public Filewriter(String string){ } public static void main(String[] args)throws IOException { long time =System.currentTimeMillis(); Filewriter filewriter=new Filewriter("text"); int num; for(int i=0;i<=10000;i++){ num=(int)Math.random()*10000; filewriter.write(num+" "); } filewriter.close(); time=System.currentTimeMillis()-time; System.out.println("使用Filewriter所用时间:"+time+"um"); } private void write(String string){ } private void close(){ } } 1流的概念 stream代表的是任何有能力产出数据的数据源,或是任何有能力接收数据的接收源。流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样,如下图: 在Java的IO中,所有的stream(包括Inputstream和Out stream)都包括两种类型: (1)字节流 表示以字节为单位从stream中读取或往stream中写入信息,即io包中的inputstream类和outputstream类的派生类。通常用来读取二进制数据,如图象和声音。 (2)字符流 以Unicode字符为导向的stream,表示以Unicode字符为单位从stream中读取或往stream中写入信息。 区别: Reader和Writer要解决的,最主要的问题就是国际化。原先的I/O类库只支持8位的字节流,因此不可能很好地处理16位的Unicode字符流。Unicode是国际化的字符集(更何况Java内置的char就是16位的Unicode 字符),这样加了Reader和Writer之后,所有的I/O就都支持Unicode了。此外新类库的性能也比旧的好。 但是,Read和Write并不是取代InputStream和OutputStream,有时,你还必须同时使用"基于byte的类"和"基于字符的类"。为此,它还提供了两个"适配器(adapter)"类。InputStreamReader负责将InputStream转化成Reader,而OutputStreamWriter则将OutputStream转化成Writer。实际上是通过byte[]和String来关联。在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的。 以字符为导向的stream基本上对有与之相对应的以字节为导向的stream。两个对应类实现的功能相同,只是在操作时的导向不同。 实验四 Java 输入输出流 1.实验目的 (1) 掌握输入输出流的总体结构; (2) 掌握流的概念; (3) 了解各种流(包括文件流、过滤流、对象的序列化、随机访问)的使用。2.实验内容 实验题1 编写一个Java Application程序,打印命令行输入的所有参数。 [基本要求] 编写完整程序。 运行结果: 代码如下: import java.util.Scanner; public class CommandOutPut { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("Please input :"); Scanner in = new Scanner(System.in); String str = in.nextLine(); System.out.println("The output results :"); System.out.println(str); in.close(); } } 实验题2 通过键盘输入路径,搜索指定路径下的全部内容。 运行结果: 代码如下: package https://www.wendangku.net/doc/1518221120.html,.output; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class Output { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub String fileName = "d:\\xxx.txt"; File file = new File(fileName); byte[] b=new byte[(int)file.length()]; FileInputStream out=new FileInputStream(file); 班级:13科技2班学号:201324131225 姓名:许耿宁 Java多线程和输入输出流 一、实验目的: 1.熟悉利用Thread类建立多线程方法。 2.熟悉利用Thread接口建立多线程方法。 3.熟悉Java的文件读写机制,练习输入输出流的使用。 二、实验内容: 1.阅读下列程序,分析并上机检验其功能。 public class DelayRunnable implements Runnable{ private static int count=0; private int no; private int delay; public DelayRunnable(){ count++; no=count; } public void run(){ try{ for (int i=0;i<10;i++){ delay=(int)(Math.random()*5000); Thread.sleep(delay); System.out.println("Thread "+no+" with a delay "+delay); } }catch(InterruptedException e){} } } class MyRunnable{ public static void main(String args[]){ DelayRunnable r1 = new DelayRunnable(); DelayRunnable r2 = new DelayRunnable(); Thread thread1=new Thread(r1); Thread thread2=new Thread(r2); thread1.start(); thread2.start(); try{ Thread.sleep(1000); }catch(InterruptedException e){ System.out.println("Thread wrong"); } } } 2.将上列程序利用Runnable接口改写,并上机检验。 3.创建简单的程序ThreeThread.java,该程序将创建三个线程,每个线程应当显示它所运行的时间(可以考虑使用Date类或Calendar类)。 4.键盘输入10个整数,从小到大进行排序。 5.接收键盘输入的字符串,用FileInputStream类将字符串写入文件,用 FileOutputStream类读出文件内容显示在屏幕上。 6.将一个文本文件的内容按行读出,每读出一行就顺序加上行号,并写入到另一个文件中。 三、实验要求: 1.通过实验掌握Thread 、Runnable使用方法; 2.程序必须能够实现多线程; 3.程序必须能够完成题目要求; 4.通过实验掌握文件输入输出流的使用方法; 5.程序必须能够从键盘接收字符串并保存在文件中; 6.程序必须能够读出文件内容显示在屏幕上; 7.写出实验报告。 四、实验代码及截图: 第一题: 在编译器上运行程序得到截图所示结果: ▇▆大学计算机与信息技术学院 实验报告 姓名□□□学号▅▅▅▅专业班级▅▅ 课程名称 Java实验实验日期???? 成绩指导教师▇▇██批改日期实验名称实验9 Java的输入输出流 ●实验目的 1. 理解I/O流的概念,掌握其分类 2. 掌握文本文件读写、二进制文件读写 ●实验内容 1. 分别使用FileWriter 和BufferedWriter 往文件中写入1万个随机数,比较用时的多少?(用时采用方法System.currentTimeMillis())求时间差; 使用:FileWriter 程序源代码 import java.io.*; public class TestFileWriter { public static void main(String []args) throws IOException{ File f = new File("C:/java/tem.txt"); if (f.exists()){ System.out.printf("文件\"C:/java/tem.txt\"已存在"); System.exit(0); } FileWriter fileWriter = new FileWriter(f); long time = System.currentTimeMillis(); for(int i=0;i<10000;i++) fileWriter.write((int)(Math.random()*101)); fileWriter.close(); time = System.currentTimeMillis() - time; System.out.printf("使用FileWriter耗时:"+time+"毫秒"); } } 程序运行结果贴图 使用:BufferedWriter 程序源代码 import java.io.*; public class TestBufferedWriter { public static void main(String []args) throws IOException{ File f = new File("C:/java/tem2.txt"); Java IO流和文件操作Java流操作有关的类或接口: Java流类图结构: 1、File类 File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。 构造方法摘要 File(File parent, String child) File(String pathname) File(String parent, String child) 构造函数 创建方法 1.boolean createNewFile() 不存在返回true 存在返回false 2.boolean mkdir() 创建目录 3.boolean mkdirs() 创建多级目录 删除方法 1.boolean delete() 2.boolean deleteOnExit() 文件使用完成后删除 例子1:列出指定文件夹的文件或文件夹 public class FileDemo1 { public static void main(String[] args){ File[] files =File.listRoots(); for(File file:files){ System.out.println(file); if(file.length()>0){ String[] filenames =file.list(); for(String filename:filenames){ System.out.println(filename); } } } } } 例子2:文件过滤 import java.io.File; public class FileTest2 { public static void main(String[] args) { File file = new File("file"); String[] names = file.list(); for(String name : names) { if(name.endsWith(".java")) { System.out.println(name); } 软件091班java程序机试题 编程题: 0. 求两点之间的距离。 要求: 1)设计点类,属性为点的坐标;利用点类设计距离类。 2)两点的坐标通过键盘输入,键盘输入要运用流,输入数据时要有合理的提示信息, 输出信息表达明确。 1.实现如下界面功能的图形界面应用程序(字体设置)。 2.编写程序,通过键盘输入多行信息,直接输入一个文本文件中。 要求:键盘输入的信息要使用流。 3.求5个以上学生的Java平均成绩。 要求: 1)要利用对象数组生成对象 2)信息通过键盘输入(利用流)。 3)Java成绩的范围在0-分100分,若输错,则需要重新输入。 4.设计一个包含两个命令按钮(显示文字和显示图片)的界面。 要求: 1)当单击“显示文字”命令按钮后,命令按钮变为“文字消失”,同时显示一行“单 击了命令按钮!”的文字。单击“文字消失”命令按钮后,命令按钮又变为“显 示文字”命令按钮,同时文字“单击了命令按钮!”消失。如此可以反复。 2)当单击“显示图片”命令按钮后,命令按钮变为“图片消失”,同时显示任意一 幅图片。单击“图片消失”命令按钮后,命令按钮又变为“显示图片”命令按钮, 同时图片消失。如此可以反复。 5.求5个以上人的平均年龄。 要求: 1)要利用对象数组生成对象 2)信息通过键盘输入(利用流)。 3)人年龄的范围在0岁-120岁,若输错,则需要重新输入。 6.打开Login1.Java源程序,题目要求见源程序的注释部分。 7.分别利用接口和抽象类,求给定三个以上三角形和给定三个以上矩形的平均周长。 提示:应该产生两个源程序。 要求: 1)要利用对象数组生成对象。 2)信息通过键盘输入(利用流)。 3)输入的三角形的三条边要能构成三角形,否则需要重新输入。 一、数据流的基本概念 流一般分为输入流(Input Stream)和输出流(Output Stream)两类,但这种划分并不是绝对的。比如一个文件,当向其中写数据时,它就是一个输出流;当从其中读取数据时,它就是一个输入流。当然,键盘只是一个数人流,而屏幕则只是一个输出流。 java的标准数据流:标准输入输出指在字符方式下(如DOS),程序与系统进行交互的方式,分为三种: 标准输入studin,对象是键盘。 标准输出stdout,对象是屏幕。 标准错误输出stderr,对象也是屏幕。 二、java.io包中的数据流和文件类 字节流:从InputStream和OutputStream派生出来的一系列类。这类流以字节(byte)为基本处理单位。 InputStream、OutputStream FileInputStream、FileOutputStream PipedInputStream、PipedOutputStream ByteArrayInputStream、ByteArrayOutputStream FilterInputStream、FilterOutputStream DataInputStream、DataOutputStream BufferedInputStream、BufferedOutputStream 字符流:从Reader和Writer派生出的一系列类,这类流以16位的Unicode码表示的字符为基本处理单位。 Reader、Writer InputStreamReader、OutputStreamWriter FileReader、FileWriter CharArrayReader、CharArrayWriter PipedReader、PipedWriter FilterReader、FilterWriter BufferedReader、BufferedWriter StringReader、StringWriter 三、字节流方法 InputStream 和OutputStream read():从流中读入数据 skip():跳过流中若干字节数 available():返回流中可用字节数 mark():在流中标记一个位置 reset():返回标记过得位置 markSupport():是否支持标记和复位操作 close():关闭流 int read() :从输入流中读一个字节,形成一个0~255之间的整数返回(是一个抽象方法)。 int read(byte b[]) :读多个字节到数组中。 int read(byte b[], int off, int len):从输入流中读取长度为len的数据,写入数组b中从索引of f开始的位置,并返回读取得字节数。 write(int b) :将一个整数输出到流中(只输出低位字节,抽象) write(byte b[]) :将字节数组中的数据输出到流中 write(byte b[], int off, int len) :将数组b中从off指定的位置开始,长度为len的数据输出到流 广西科技大学 计通学院 《Java面向对象程序设计》实验实验八输入输出流 学生姓名:××× 学号:××× 班级:××× 指导老师:××× 专业:计算机科学与技术 提交日期:×××年××月××日 实验报告内容 1.实验目的 掌握字符输入、输出流用法; 掌握使用Scanner类解析文件; 掌握Console流的使用。 2.实验内容 实验教材-第12章实验1、2、3 字符输入输出流;Scanner类和Console类。 要求:完善程序,给出实验结果截图; 完成试验后练习。 3.程序代码及运行结果: 实验1 举重成绩单 //AnalysisResult.java import java.io.*; import java.util.*; public class AnalysisResult { public static void main(String[] args) { File fRead=new File("score.txt"); File fWrite=new File("scoreAnalysis.txt"); try{ Writer out=new FileWriter(fWrite); BufferedWriter bufferWrite=new BufferedWriter(out); Reader in=new FileReader(fRead); BufferedReader bufferRead=new BufferedReader(in); String str=null; while((str=bufferRead.readLine())!=null){ double 实验输入输出流 一、实验目的 1、掌握文件字节流的用法; 2、掌握文件字符流的用法; 3、掌握缓冲流的用法; 二、实验内容与步骤 1、编写程序,实现将诗句写入c:\小池.txt文件中,然后再从该文件中读出并打印输出。宋诗《小池》 作者:杨万里 泉眼无声惜细流, 树荫照水弄轻柔。 小荷才露尖尖角, 早有蜻蜓立上头。 import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Scanner; public class PoemWrite { public static void main(String[] args) { Scanner reader=new Scanner(System.in); String s; try{ FileWriter outOne=new FileWriter("c:\\小池.txt"); BufferedWriter outTwo=new BufferedWriter(outOne); while(!(s=reader.nextLine()).equals("0")){ outTwo.write(s); outTwo.newLine(); } outTwo.flush(); outTwo.close(); outOne.close(); FileReader inOne=new FileReader("c:\\小池.txt"); BufferedReader inTwo=new BufferedReader(inOne); while((s=inTwo.readLine())!=null){ 成都大学实验报告 实验项目名称Java的输入与输出流 一、实验目的: 1. 理解I/O流的概念,掌握其分类 2. 掌握文本文件读写、二进制文件读写 二、实验内容(包括源程序及相关说明): 1. 分别使用FileWriter 和BufferedWriter 往文件中写入10万个随机数,比较用时。源代码如下: (1) import java.io.*; public class Ex1_1 { public static void main(String[] args) throws IOException{ long t=System.currentTimeMillis(); FileWriter fw =new FileWriter("d:\\Ex1.txt"); for(int i=1;i<=100000;i++) { fw.write((int)(Math.random()*10000)+" \n"); } fw.close(); t=System.currentTimeMillis()-t; System.out.println("The elapsed: "+t); } } (2) import java.io.*; public class Ex1_1 { public static void main(String[] args) throws IOException{ long t=System.currentTimeMillis(); BufferedWriter fw=new BufferedWriter(new FileWriter("d:\\Ex1.txt")); 输入输出流 一、实验目的: 熟悉Java的文件读写机制,练习输入输出流的使用。 二、实验内容: 1、键盘输入10个整数,从小到大进行排序。 2、接收键盘输入的字符串,用FileInputStream类将字符串写入文件,用 FileOutputStream类读出文件内容显示在屏幕上。 3、将一个文本文件的内容按行读出,每读出一行就顺序加上行号,并写入 到另一个文件中。 三、实验要求: 1. 通过实验掌握文件输入输出流的使用方法; 2. 程序必须能够从键盘接收字符串并保存在文件中; 3. 程序必须能够读出文件内容显示在屏幕上; 4. 写出实验报告。 四、实验步骤: 1、键盘输入10个整数,从小到大进行排序。 package javaTest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Gui_21 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String str; int array[]=new int[10]; for(int i=0;i<10;i++) { System.out.println("请输入一个整数:"); str=br.readLine(); array[i]=Integer.parseInt(str); 分类:Java JSP和Servlet中的输入输出流 2008-05-27 20:00 一、servlet response实现了HttpServletResponse接口,request实现了HttpServletRequest接口。 1、输出流有两个: 字节形式输出:response.getOutputStream() 字符形式输出:response.getWriter() 2、输入流有两个: 字节形式输入:request.getInputStream() 字符形式输入:request.getReader() 二、JSP JSP中的response对象已经实现了HttpServletResponse接口,request对象已经实现了HttpServletRequest接口。 1、输出流 jsp中可以使用response.getWriter()方法建立字符输出流来输出字符数据到网页上。 因为jsp转译成servlet时,当有输出就会使用getWriter(). 它是javax.servlet.jsp.JspWriter类型(extends java.io.Writer). 而getOutputStream(). 它是javax.servlet.ServletOutputStream类型(extends java.io.OutputStream). 而对客户端的输出只能使用一种类别输出. 当它在jsp里使用了getOutputStream(). 就会产生了两种类别输出,所以就会形成冲突.program根本不知道你要使用那一个作为输出. 一般在下载档案时都要使用getOutputStream().对客户端串流输出. 使用jsp作为下载档案时, 在jsp档案里,不能有任何的输出. 包括空格或out.println("xxx"); 因为会使用了jspWriter(). 2、输入流 jsp中好像没有自动实现输入流的对象,所以可以使用request.getInputStream(),request.getReader()方法建立输入流。 3、读写服务器上的文件 file.Reader()和file.Writer()方法可以用来读写服务器上任何位置的文件。 大学实验报告 实验项目名称Java的输入与输出流 一、实验目的: 1. 理解I/O流的概念,掌握其分类 2. 掌握文本文件读写、二进制文件读写 二、实验容(包括源程序及相关说明): 1. 分别使用FileWriter 和 BufferedWriter 往文件中写入10万个随机数,比较用时。源代码如下: (1) import java.io.*; public class Ex1_1 { public static void main(String[] args) throws IOException{ long t=System.currentTimeMillis(); FileWriter fw =new FileWriter("d:\\Ex1.txt"); for(int i=1;i<=100000;i++) { fw.write((int)(Math.random()*10000)+" \n"); } fw.close(); t=System.currentTimeMillis()-t; System.out.println("The elapsed: "+t); } } (2) import java.io.*; public class Ex1_1 { public static void main(String[] args) throws IOException{ long t=System.currentTimeMillis(); BufferedWriter fw=new BufferedWriter(new FileWriter("d:\\Ex1.txt")); for(int i=1;i<=100000;i++){ 实验七输入输出流 一.实验目的和要求 目的: 1、掌握使用输入输出流进行文件的读写操作。 要求: 1、实验报告给出内容1,2的填充代码以及内容3的全部源代码。 二.实验内容 1、按程序模板要求,将注释处替换为Java程序代码。实现文件加密。 2、按程序模板要求,将注释处替换为Java程序代码。给文件的内容添加行号. 3、串行化对象Student到本地文件,并在下一次运行程序时用来初始化。(选做)三.实验环境 硬件: (1)学生用微机 (2)多媒体实验教室 软件: (1)Windows XP中文操作系统 (2)JDK控制台 四.算法描述及实验步骤 实验步骤: 1、按程序模板要求,将注释处替换为Java程序代码 该程序将已存在的文本文件加密后存入另一个文本文件中。请按模板要求,将【代码1】~【代码6】替换为Java程序代码 SecretExample.java import java.io.*; public class SecretExample { public static void main(String args[ ]) { File fileOne=new File("hello.txt"), fileTwo=new File("hello.secret"); char b[]=new char[100]; try{ FileReader in=【代码1】 // 创建指向fileOne的字符输入流 FileWriter out=【代码2】 // 创建指向fileTwo字符输出流 int n=-1; while((n=in.read(b))!=-1) { for(int i=0;i 5Java输入流与输出流 5.1单项选择题 1.实现字符流的写操作类是()。 A.FileReader B.Writer C.FileInputStream D.FileOutputStream 2. 实现字符流的读操作类是()。 A.FileReader B.Writer C.FileInputStream D.FileOutputStream 3.凡是从中央处理器流向外部设备的数据流称为() A. 文件流 B. 字符流 C. 输入流 D. 输出流 4.构造BufferedInputStream的合适参数是哪一个?()A.FileInputStream B.BufferedOutputStream C.File D.FileOuterStream 5.在编写Java Application程序时,若需要使用到标准输入输出语句,必须在程序的开头写上()语句。 A.import java.awt.* ; B.import java.applet.Applet ; C.import java.io.* ; D.import java.awt.Graphics ; 6.下列流中哪个不属于字符流?()A.InputStreamReader B.BufferedReader C.FilterReader D.FileInputStream 7.流的传递方式是() A. 并行的 B. 串行的 C. 并行和串行 D. 以上都不对 8.字符流与字节流的区别在于() A.前者带有缓冲,后者没有 B.前者是块读写,后者是字节读写 C. 二者没有区别,可以互换使用 D. 每次读写的字节数不同 9.下列流中哪个不属于字节流() A.FileInputStream B.BufferedInputStream C. FilterInputStream D. InputStreamReader 10.如果需要从文件中读取数据,则可以在程序中创建哪一个类的对象()实验9 Java输入输出流
JAVA输入输出流--字节流篇(什么时候用哪个)
实验04 Java输入输出流报告
Java多线程和输入输出流
实验9 Java输入输出流
java输入输出流和文件操作
Java输入输出流经典编程题
java输入输出流总结
《Java面向对象程序设计》实验-实验八(输入输出流)
java实验11 输入输出流 - 答案
Java的输入与输出流(实验报告)
java输入输出流试验
servlet中的输入输出流
Java的输入与输出流(实验报告)
java实验七 输入输出流
5Java第五单元练习题-输入流与输出流