第7章输入输出系统
第7章 输入输出系统7.1 I/O 流概述7.2 流的分类7.3 字节流的处理7.4 字符流的处理7.5 文件处理7.6 对象的串行化7.7 输入输出程序例幻灯片27.1 I/O 流概述l 在Java中,把所有的输入和输出都当做流来处理 "流"是一个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象"流"屏蔽了实际的输入/输出设备中处理数据的细节l 一个程序可以打开一个数据源上的流,然后按顺序读取这个流中的数据到程序中,这样的流称为输入流;一个程序也可以打开一个目的地的流,然后按顺序的把程序中的数据写入到这个目的地中,这样的流称为输出流,其过程如图所示幻灯片3l JDK 提供了包java.io,其中包括一系列的类来实现输入/输出处理幻灯片47.2 流的分类l Java的输入/输出流中,根据它们的数据类型,主要可分为两类:字节流(Btye Stream)和字符流(Character Stream)l 在java.io中包含子类较多的有“四大家族”,它们分别是l InputStream, OutputStreaml Reader, Writer幻灯片51. 字节流l 字节流是按字节读/写二进制数据。
l 字节流有两个基本的类:InputStream类和OutputStream类InputStream类用于处理字节输入流,OutputStream类用于处理字节输出流,这两个都是抽象类l 从InputStream和OutputStream派生出来的一系列类这类流以字节(byte)为基本处理单位 幻灯片6幻灯片82. 字符流l 字符流的输入/输出数据是字符码,即Unicode字符l 字符流有两个基本类:Reader类和Writer类Reader类用于处理字符输入流,Writer类用于处理字符输出流l 从Reader和Writer派生出的一系列类,这类流以16位的Unicode码表示的字符为基本处理单位 幻灯片10幻灯片113. 其它l 文件处理:l File、RandomAccessFile;l 接口:l DataInput、DataOutput、ObjectInput、ObjectOutput;幻灯片127.3 字节流的处理1. InputStreaml ◇ 从流中读取数据:l int read( ) //读取一个字节,返回值为所读的字节l int read( byte b[ ] ) //读取多个字节,放置到字节数组b中,通常读取的字节数量为b的长度,返回值为实际读取的字节的数量l int read( byte b[ ], int off, int len ) //读取len个字节,放置到以下标off开始字节数组b中,返回值为实际读取的字节的数量 l int available( ) //返回值为流中尚未读取的字节的数量l long skip( long n ) //读指针跳过n个字节不读,返回值为实际跳过的字节数量幻灯片13l ◇ 关闭流:l close( ) //流操作完毕后必须关闭l l ◇ 使用输入流中的标记:l void mark( int readlimit ) //记录当前读指针所在位置,readlimit表示读指针读出readlimit个字节后所标记的指针位置才失效l void reset( ) //把读指针重新指向用mark方法所记录的位置l boolean markSupported( ) //当前的流是否支持读指针的记录功能幻灯片142.OutputStreaml ◇ 输出数据:l void write( int b ) //将指定的字节写入此输出流,要写入的字节是参数 b 的八个低位。
b 的 24 个高位将被忽略l void write( byte b[ ] ) //将 b.length 个字节从指定的字节数组写入此输出流l void write( byte b[ ], int off, int len ) //把字节数组b中从下标off开始,长度为len的字节写入流中 l ◇ flush( ) //刷空输出流,并输出所有被缓存的字节由于某些流支持缓存功能,该方法将把缓存中所有内容强制输出到流中l l ◇ 关闭流:l close( ) //流操作完毕后必须关闭幻灯片153. 标准流l 在Java程序开始执行时,Java会创建三个与设备相关联的流对象:System.in、System.out和System.errl System.in 标准输入流,类型是InputStreaml 对象使程序能够读取来自键盘的输入;l System.out 标准输出流,类型是PrintStreaml 对象使程序能够向屏幕输出数据;l System.err 标准错误流,类型是PrintStreaml 对象使程序能够向屏幕输出错误信息幻灯片16l 每种标准流都可以被重定向。
对System.in进行重定向,程序能够从其它数据源读取数据;对System.out和System.err进行重新定向,使程序能够将输出数据和错误信息发送到其它的位置,比如磁盘上的某个文件l 例:P152幻灯片174. 在使用输入输出流类时,有两个语句总是要注意的:l 一是导入java.io包(import java.io.*;);l 二是对IOException异常的处理,一般是在调用的方法的声明时"throws IOException",当然也可以用try-catch语句进行异常处理幻灯片185. 过滤流l 过滤流在读/写数据的同时可以对数据进行处理,它将其它流用作其基本数据源,它可以直接传输数据或提供一些额外的功能l 类FilterInputStream和FilterOutputStream分别作为所有过滤输入流和输出流的父类幻灯片19l 为了使用一个过滤流,必须首先把过滤流连接到某个输入/出流上,通常通过在构造方法的参数中指定所要连接的输入/出流来实现例如:l FilterInputStream( InputStream in );l FilterOutputStream( OutputStream out );幻灯片20几种常见的过滤流l ◇ BufferedInputStream和BufferedOutputStreaml 缓冲流,用于提高输入/输出处理的效率。
l ◇ DataInputStream 和 DataOutputStreaml 不仅能读/写数据流,而且能读/写各种的java语言的基本类型,如:boolean,int,float等l ◇ LineNumberInputStreaml 除了提供对输入处理的支持外,LineNumberInputStream可以记录当前的行号l ◇ PushbackInputStreaml 提供了一个方法可以把刚读过的字节退回到输入流中,以便重新再读一遍l ◇PrintStreaml 输出各种数据值表示形式幻灯片21BufferedInputStreaml BufferedInputStream(InputStream in) l 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用 l BufferedInputStream(InputStream in, int size) l 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使 幻灯片22BufferedOutputStreaml BufferedOutputStream(OutputStream out) l 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
l BufferedOutputStream(OutputStream out, int size) l 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流 幻灯片23DataInputStreaml DataInputStream(InputStream in) l 使用指定的底层 InputStream 创建一个 DataInputStreaml int read(byte[] b) l boolean readBoolean() l byte readByte() l char readChar() l double readDouble() l float readFloat() l int readInt() 幻灯片24DataOutputStreaml DataOutputStream(OutputStream out) l 创建一个新的数据输出流,将数据写入指定基础输出流l void writeBoolean(boolean v) l void writeByte(int v) l void writeBytes(String s) l void writeChar(int v) l void writeChars(String s) l void writeDouble(double v) l void writeFloat(float v) l void writeInt(int v) l void writeLong(long v) l void writeShort(int v) 幻灯片25PrintStreaml PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式(字符)。
它还提供其他两项功能:l 与其他输出流不同,PrintStream 永远不会抛出 IOException,而是异常情况仅设置可通过 checkError 方法测试的内部标志l 自动刷新幻灯片26l PrintStream(File file) l 创建具有指定文件且不带自动行刷新的新打印流 l PrintStream(File file, String csn) l 创建具有指定文件名称和字符集且不带自动行刷新的新打印流 l PrintStream(OutputStream out) l 创建新的打印流 l PrintStream(OutputStream out, boolean autoFlush) l 创建新的打印流 l PrintStream(OutputStream out, boolean autoFlush, String encoding) l 创建新的打印流 l PrintStream(String fileName) l 创建具有指定文件名称且不带自动行刷新的新打印流 l PrintStream(String fileName, String csn) l 创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
幻灯片276. FileInputStreaml 从文件系统中的某个文件中获得输入字节l FileInputStream(File file) l 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定 l FileInputStream(String name) l 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定幻灯片287. FileOutputStream文件输出流是用于将数据写入 File 的输出流FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流 FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流 FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流 FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的输出文件流。
幻灯片29例:l 在data文件中写入一个int值、一个double值和一个字符l 从data文件中读入上述三个值,并在屏幕上显示出来幻灯片30class Test{ public static void main(String[] args) throws IOException{ FileOutputStream fout=new FileOutputStream("data"); BufferedOutputStream bout=new BufferedOutputStream(fout); DataOutputStream dout=new DataOutputStream(bout); dout.writeInt(23); dout.writeDouble(56.6); dout.writeChar('k'); dout.flush();幻灯片31 FileInputStream fin=new FileInputStream("data.txt"); BufferedInputStream bufin=new BufferedInputStream(fin); DataInputStream din=new DataInputStream(bufin); int a=din.readInt(); double b=din.readDouble(); char c=din.readChar(); System.out.println(a); System.out.println(b); System.out.println(c); dout.close(); din.close(); }}幻灯片327.4 字符流的处理l java中提供了处理以16位的Unicode码表示的字符流的类,即以Reader和Writer 为基类派生出的一系列类。
幻灯片337.4.1 Reader和Writerl 这两个类是抽象类,只是提供了一系列用于字符流处理的接口,不能生成这两个类的实例,只能通过使用由它们派生出来的子类对象来处理字符流幻灯片341.Reader类是处理所有字符流输入类的父类l 读取字符 l public int read() throws IOException; //读取一个字符,返回值为读取的字符l public int read(char cbuf[]) throws IOException; /*读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量*/l public abstract int read(char cbuf[],int off,int len) throws IOException; /*读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现*/l 标记流l public boolean markSupported(); //判断当前流是否支持做标记l public void mark(int readAheadLimit) throws IOException; //给当前流作标记,最多支持readAheadLimit个字符的回溯。
l public void reset() throws IOException; //将当前流重置到做标记处l 关闭流l public abstract void close() throws IOException;幻灯片352.Writer类是处理所有字符流输出类的父类◇ 向输出流写入字符 public void write(int c) throws IOException; //将整型值c的低16位写入输出流 public void write(char cbuf[]) throws IOException; //将字符数组cbuf[]写入输出流 public abstract void write(char cbuf[],int off,int len) throws IOException; //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流 public void write(String str) throws IOException; //将字符串str中的字符写入输出流 public void write(String str,int off,int len) throws IOException; //将字符串str 中从索引off开始处的len个字符写入输出流幻灯片36l ◇ flush( )l 刷空输出流,并输出所有被缓存的字节。
l ◇ 关闭流l public abstract void close() throws IOException;幻灯片377.4.2 InputStreamReader和OutputStreamWriterl java.io包中用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介l ◇ 生成流对象l public InputStreamReader(InputStream in); l /*in是字节流,而InputStreamReader是字符流,但是其来源是字节流in,因此InputStreamReader就可以把字节流in转换成字符流处理/*l public InputStreamReader(InputStream in,String enc) throws UnsupportedEncodingException;l /*enc是编码方式,就是从字节流到字符流进行转换时所采用的编码方式,例如 ISO8859-1,UTF-8,UTF-16等等*/幻灯片38l public OutputStreamWriter(OutputStream out);l //out是字节流,而OutputStreamReader是字符流l public OutputStreamWriter(OutputStream out,String enc) throws UnsupportedEncodingException; l //enc是编码方式幻灯片39l InputStreamReader和OutputStreamWriter的方法:l ◇ 读入和写出字符l 基本同Reader和Writer。
l ◇ 获取当前编码方式l public String getEncoding();l ◇ 关闭流l public void close() throws IOException;幻灯片40l class Test{l public static void main(String[] args) throws IOException{l InputStreamReader inr=new InputStreamReader(System.in);l System.out.println(inr.read());l System.out.println(inr.getEncoding());l }l }幻灯片417.4.3 BufferedReader和BufferedWriterl ◇ 生成流对象l public BufferedReader(Reader in); //使用缺省的缓冲区大小l public BufferedReader(Reader in, int sz); //sz为缓冲区的大小l public BufferedWriter(Writer out);l public BufferedWriter(Writer out, int sz);l ◇ 读入/写出字符l 除了Reader和Writer中提供的基本的读写方法外,增加对整行字符的处理。
l public String readLine() throws IOException; //读一行字符l public void newLine() throws IOException; //写一行字符幻灯片42输出:123Input value is 123Input value changed after doubled: 246例:l import java.io.*;l public class NumberInput{l public static void main(String args[]){l try{l InputStreamReader ir;l BufferedReader in;l ir=new InputStreamReader(System.in);l in=new BufferedReader(ir);l String s=in.readLine();l System.out.println("Input value is: "+s);l int i = Integer.parseInt(s); //转换成int型l i*=2;l System.out.println("Input value changed after doubled: "+i);l }catch(IOException e){l System.out.println(e);l }l }l }幻灯片437.4.3 FileReader和FileWriterl FileReader(File file) l 在给定从中读取数据的 File 的情况下创建一个新 FileReader。
l FileReader(String fileName) l 在给定从中读取数据的文件名的情况下创建一个新 FileReader 幻灯片44l FileWriter(File file) l 根据给定的 File 对象构造一个 FileWriter 对象 l FileWriter(File file, boolean append) l 根据给定的 File 对象构造一个 FileWriter 对象 l FileWriter(String fileName) l 根据给定的文件名构造一个 FileWriter 对象 l FileWriter(String fileName, boolean append) l 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象 幻灯片45例:l 将各种类型的数据写到文件“data.txt”,然后读出并显示到屏幕l 要求使用“utf-8”编码幻灯片46l class Test{l public static void main(String[] args) throws IOException{l PrintWriter pw=new PrintWriter("data.txt","utf-8");l pw.print(23);l pw.println(); //换行l pw.println("中国");l pw.flush();幻灯片47l InputStreamReader ins=new InputStreamReader(new FileInputStream("data.txt"),"utf-8");l BufferedReader br=new BufferedReader(ins);l String str=null;l l while((str=br.readLine())!=null){l System.out.println(str);l }l }l }幻灯片487.6 文件处理l I/O处理中,最常见的是对文件的操作,java.io包中有关文件处理的类有:File、FileInputStream、FileOutputStream、RamdomAccessFile等。
幻灯片497.6.1 文件描述l 类File提供了一种与机器无关的方式来描述一个文件对象的属性下面我们介绍类File中提供的各种方法l ◇ 文件或目录的生成l public File(String path);l /*如果path是实际存在的路径,则该File对象表示的是目录;如果path是文件名,则该File对象表示的是文件/l public File(String path,String name);//path是路径名,name是文件名l public File(File dir,String name);//dir是目录对象,name是文件名幻灯片50l ◇ 文件名的处理l String getName( ); //得到一个文件的名称(不包括路径)l String getPath( ); //得到一个文件的路径名l String getAbsolutePath( );//得到一个文件的绝对路径名l String getParent( ); //得到一个文件的上一级目录名l String renameTo(File newName); //将当前文件名更名为给定文件的完整路径幻灯片51l ◇ 文件属性测试l boolean exists( ); //测试当前File对象所指示的文件是否存在l boolean canWrite( );//测试当前文件是否可写l boolean canRead( );//测试当前文件是否可读l boolean isFile( ); //测试当前文件是否是文件(不是目录)l boolean isDirectory( ); //测试当前文件是否是目录幻灯片52l ◇ 普通文件信息和工具l long lastModified( );//得到文件最近一次修改的时间l long length( ); //得到文件的长度,以字节为单位l boolean delete( ); //删除当前文件幻灯片53l ◇ 目录操作l boolean mkdir( ); l //根据当前对象生成一个由该对象指定的路径l String[ ] list( ); l //列出当前File对象表示的目录中的文件和目录目录下的文件l String[ ] list(FilenameFilter filter) l //列出当前File对象表示的目录中满足指定过滤器的文件和目录。
幻灯片54例:列出目录D:\temp\所有的.java文件l import java.io.*;l class Filter implements FilenameFilter{l String extent;l Filter(String extent){l this.extent=extent;l }l public boolean accept(File dir,String name){l return name.endsWith("."+extent); }l }幻灯片55public class FileFilterTest{ public static void main(String args[]){ File dir=new File("d:\\temp"); //用File 对象表示一个目录 Filter filter=new Filter("java"); //生成过滤器 System.out.println("list java files in directory "+dir); String files[]=dir.list(filter); //列出目录dir下,文件后缀名为java的所有文件 for(int i=0;i 例如,下列的程序是顺序读取文件名为text.txt的文件里的内容,并显示在控制台上面,直到文件结束为止幻灯片57l import java.io.*;l public class test{l public static void main(String args[]){l FileInputStream fis;l try{l fis = new FileInputStream( "d:\\temp\\text.txt" );l System.out.print( "content of text is : ");l int b;l //顺序读取文件text里的内容并赋值给整型变量b,直到文件结束为止l while( (b=fis.read())!=-1 )l System.out.print( (char)b );l }catch( FileNotFoundException e ){l System.out.println( e );l }catch( IOException e ){l System.out.println( e );l }l }l }幻灯片587.6.3 随机访问文件l 对于InputStream 和OutputStream 来说,它们的实例都是顺序访问流,也就是说,只能对文件进行顺序地读/写。 随机访问文件则允许对文件内容进行随机读/写l 在java中,类RandomAccessFile 提供了随机访问文件的方法类RandomAccessFile的声明为:l public class RandomAccessFile extends Object implements DataInput, DataOutput幻灯片59l 接口DataInput 中定义的方法主要包括从流中读取基本类型的数据、读取一行数据、或者读取指定长度的字节数如:readBoolean( )、readInt( )、readLine( )、readFully( ) 等 l 接口DataOutput 中定义的方法主要是向流中写入基本类型的数据、或者写入一定长度的字节数组如:writeChar( )、writeDouble( )、write( ) 等 下面详细介绍RandomAccessFile类中的方法幻灯片60◇ 构造方法: RandomAccessFile(String name,String mode); //name是文件名,mode是打开方式,例如"r"表示只读,"rw"表示可读写," RandomAccessFile(File file,String mode); //file是文件对象◇ 文件指针的操作 long getFilePointer( ); //用于得到当前的文件指针 void seek( long pos ); //用于移动文件指针到指定的位置 int skipBytes( int n ); //使文件指针向前移动指定的n个字节应用例:P164幻灯片61例:显示指定文本文件最后n个字符。 文本文件名和数字n用命令行参数的方式提供幻灯片62import java.io.*;public class test { public static void main(String[] args){ try{ RandomAccessFile raf=new RandomAccessFile(args[0],"r"); long count=Long.valueOf(args[1]).longValue(); long position=raf.length(); position-=count; if(position<0) position=0; raf.seek(position); while(true){ try{ byte b=raf.readByte(); System.out.print((char)b); }catch(EOFException eofe){ break; } } }catch(Exception e){ e.printStackTrace(); } } }幻灯片637.7 对象的串行化幻灯片647.7.1 串行化的定义1. 什么是串行化l 对象的寿命通常随着生成该对象的程序的终止而终止。 有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复我们把对象的这种能记录自己的状态以便将来再生的能力,叫做对象的持续性(persistence)对象通过写出描述自己状态的数值来记录自己,这个过程叫对象的串行化(Serialization)幻灯片652. 串行化的目的l 串行化的目的是为java的运行环境提供一组特性:l 尽量保持对象串行化的简单扼要 ,但开发者可进行扩展或定制l 串行化机制应严格遵守Java的对象模型 对象的串行化状态中应该存有所有的关于种类的安全特性的信息l 对象的串行化机制应支持Java的对象持续性l 对象的串行化机制应有足够的 可扩展能力以支持对象的远程方法调用(RMI)l 对象串行化应允许对象定义自身的格式即其自身的数据流表示形式,可外部化接口来完成这项功能l 串行化主要任务是写出对象实例变量的数值幻灯片667.7.2 串行化方法l 在java.io包中,接口Serializable用来作为实现对象串行化的工具,只有实现了Serializable的类的对象才可以被串行化l Serializable接口没有方法或字段,仅用于标识可序列化的语义幻灯片671. 定义一个可串行化对象class Student implements Serializable{ int id; //学号 String name; //姓名 int age; //年龄 String department; //系别 public Student(int id,String name,int age,String department){ this.id = id; this.name = name; this.age = age; this.department = department; }}幻灯片682. 构造对象的输入/输出流l 要串行化一个对象,必须与一定的对象输入/输出流联系起来,通过对象输出流将对象状态保存下来,再通过对象输入流将对象状态恢复。 l java.io包中,提供了ObjectInputStream和ObjectOutputStream将数据流功能扩展至可读写对象l 在ObjectInputStream中用readObject()方法可以直接读取一个对象l ObjectOutputStream中用writeObject()方法可以直接将对象保存到输出流中l ObjectInputStream(InputStream in)l ObjectOutputStream(OutputStream out)幻灯片69public class test{ public static void main(String args[]) throws Exception{ Student stu1=new Student(981036,"Liu Ming",18, "CSD"); //保存对象的状态 FileOutputStream fo=new FileOutputStream("d:\\temp\\data.bin"); ObjectOutputStream so=new ObjectOutputStream(fo); so.writeObject(stu1); so.close(); //恢复对象的状态 FileInputStream fi=new FileInputStream("d:\\temp\\data.bin"); ObjectInputStream si=new ObjectInputStream(fi); Student stu2=(Student)si.readObject(); si.close(); System.out.println(stu2.name); }}幻灯片70l 在这个例子中,我们首先定义一个类Student,实现了 Serializable接口,然后通过对象输出流的writeObject()方法将Student对象保存到文件d:\temp\data.bin中。 之后,通过对象输入流的readObject()方法从文件d:\temp\data.bin中读出保存下来的Student对象幻灯片717.7.3 串行化的注意事项l 1. 串行化能保存的元素l 只能保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量,而且串行化保存的只是变量的值,对于变量的任何修饰符,都不能保存l 2. transient关键字 l 对于某些类型的对象,其状态是瞬时的,这样的对象是无法保存其状态的,例如一个Thread对象,或一个FileInputStream对象,对于这些字段,我们必须用transient关键字标明幻灯片72l 3. 定制串行化l 缺省的串行化机制,对象串行化首先写入类数据和类字段的信息,然后按照名称的上升排列顺序写入其数值如果想自己明确地控制这些数值的写入顺序和写入种类,必须定义自己的读写数据流的方式就是在类的定义中l 重写writeObject()和readObject()方法l 例如可在前面的例子中,加入重写的writeObject()和readObject()方法,对Student 类定制其串行化幻灯片73class Student implements Serializable{ int id; //学号 String name; //姓名 int age; //年龄 String department; //系别 public Student(int id,String name,int age,String department){ this.id = id; this.name = name; this.age = age; this.department = department; }幻灯片74 private void writeObject(ObjectOutputStream out) throws IOException{ out.writeInt(id); out.writeInt(age); out.writeUTF(name); out.writeUTF(department); } private void readObject(ObjectInputStream in) throws IOException{ id=in.readInt(); age=in.readInt(); name=in.readUTF(); department=in.readUTF(); }}幻灯片757.8 输入输出程序例幻灯片76l public class Test {l public static void main(String args[]) throws Exception {l RandomAccessFile raf1, raf2;l File f = new File("text1.txt");l raf1 = new RandomAccessFile(f, "r");l raf2 = new RandomAccessFile("text2.txt", "rw");l long len1 = raf1.length();l long len2 = raf2.length();l raf2.seek(len2);l long fpt1 = 0;l raf2.writeBytes("" + '\n');l while (fpt1 < len1) {l String str = raf1.readLine();l raf2.writeBytes(str + '\n');l fpt1 = raf1.getFilePointer();l }l raf1.close();l raf2.close();l }l }例1:幻灯片77P178-10l import java.io.*;l public class test{l public static void main(String args[]) throws IOException{l if(args.length<3)l return;l String dir=args[0];l File directory=new File(dir);l File[] files=directory.listFiles();l l for(int i=0;i




