文件与IO
1、file类
-
基本概念
- file类:表示文件和目录路径名的抽象表示;
- file类可以实现文件的创建、删除‘、重命名、得到路径、创建时间等等,是唯一与文件本身有关的操作类;
-
file类的操作方法
-
表示路径分隔符: public static final String separator
-
构造file类实例,要传入路径 : public File(String pathname)
-
创建新文件 :public boolean creatNewFile()
-
删除文件 :public boolean delete()
-
判断给定的路径是否是文件夹/文件 : public boolean isDirectory() / isFile()
-
列出文件夹中的文件:public String[] list[]
-
列出文件夹中的所有文件,以file对象返回 :public File[] listFiles[]
-
创建新的文件夹 : public boolean mkdir()
-
返回文件大小 : public long length()
-
为文件重命名 :public boolean renameTo(File dest)
-
路径名字符串 : public getPath()
-
案例演示
public class FileDemo { public static void main(String[] args) { File fi = new File("e:"+File.pathSeparator+"java"+File.pathSeparator+"Test_case"+File.pathSeparator+"fistIOFile"); if(!fi.exists()){ try { fi.createNewFile();//创建文件 System.out.println("文件创建成功"); } catch (IOException e) { e.printStackTrace(); } } System.out.println("fi是否是文件呢?:"+fi.isDirectory()); File f2 =new File("e:\\java\\Test_case\\testio"); boolean del = f2.delete(); System.out.println("文件是否删除?:"+del);//删除文件夹需要清除里面内容 String[] filenames = f2.list(); //打印文件夹下的所有文件名 System.out.println(Arrays.toString(filenames)); //列出当前目录下的所有文件,以file对象返回 File[] fs = f2.listFiles(); System.out.println(Arrays.toString(fs)); for (File f:fs){ System.out.println("length="+f.length()); System.out.println("name="+f.getName()); System.out.println("相对路径="+f.getPath()); System.out.println("绝对路径="+f.getAbsolutePath()); Date date =new Date(f.lastModified()); DateFormat df =new SimpleDateFormat("HH:mm:ss"); System.out.println("文件最后修改的时间"+df.format(date)); } //创建一个文件夹 File f3 =new File("e:\\java\\Test_case\\testio\\newdectory"); f3.mkdir(); //给文件夹改名 f3.renameTo(new File("e:\\java\\Test_case\\testio\\alchange")); System.out.println(f3.getName()); } }
-
2、字节流
-
IO流
- IO流:输入输出流(Input/Output)
- 流失一组有顺序的,有起始和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流
-
IO流的分类
- 根据处理数据类型的不同分为:字符流和字节流
- 根据数据流向不同分为:输入流和输出流
-
字节输出流
- OutputStream类定义 public abstract class OutputStream extends Object implements Closeable,Flushable
- 此类抽象类是表示输出字节流的所有类的超类。输出流接收输出字节并将这些字节发送到inputStream类某接收器
- 要向文件中输出,使用FileOutPutStream类
//输出流 public static void main(String[] args) { out(); in(); } //输出流 private static void out(){ //确定目标文件 File file =new File("E:\\java\\简单案例\\123.txt"); //构建一个输出流对象 try{ OutputStream out = new FileOutputStream(file,true);//append=ture表示追加内容,不覆盖 //写入输出内容 String info = "我在你家学java\r\n";//“\r\n”表示换行 out.write(info.getBytes()); //关闭流 out.close(); System.out.println("输出完成!!"); } catch (FileNotFoundException e){ e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
-
字节输入流
- 定义: public abstract class InputStream extends Object impements Closeable
- 此抽象类是表示字节输入流的所有类的超类
- FileInputStream 从文件系统中的某个文件中获得输入字节
//输入流 private static void in(){ File file = new File("E:\\java\\简单案例\\123.txt"); //构建一个输入流对象 try { InputStream in = new FileInputStream(file); //定义一个1M字节的数组 byte[] bytes = new byte[1024*10]; StringBuilder buffer = new StringBuilder(); int len = 1;//每次读取的字节长度 //把数据读入数组中返回字节数,当不等于-1时,表示读取数据,等于-1表示读完 while((len=in.read(bytes))!=-1){ //将读到的字节数组,再转换成字符串内容,添加到StringBuilder中 buffer.append(new String(bytes,0,len)); } System.out.println(buffer); in.close(); System.out.println("写入成功!!!"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
-
输入输出字节流的操作原理,每次只会操作一个字节,(从文件中读取或者写入)
字节操作流:默认每次执行写入操作会直接把数据写入1文件
3、字符流
-
Writer
- 写入字符流的抽象类。子类必须实现的方法有write(char[],int,int)、flush() 和 close();但是,多数子类将重写此处定义的一些方法,以提供更高效率或其他功能。
- 与OutputStream一样,对文件的操作使用,用FileWrite类文成。
-
Reader
- 用于读取字符流的抽象类,子类必须实现的方法只有read(char[],int,int) 和 close();但是 多数子类将重写此处定义的一些方法,以提供更高效率或其他功能。
- 使用FileReader类进行实例化操作。
-
注意
- 每次操作的单位是一个字符;
- 文件字符操作流会自带缓存,默认大小为1024k,在缓存满后,或手动刷新缓存,或关闭流时会把数据写入文件;
-
字节流与字符流之间的选择
- 一般操作非文本文件时,使用字节流,操作文本文件时,建议使用字符流;
//字符流
System.out.println(cs);
public class CharStreamDemo {
public static void main(String[] args) {
out();
in();
}
//输出
private static void out(){
File file =new File("E:\\java\\简单案例\\123.txt");
try {
Writer out = new FileWriter(file,true);
out.write("你在大厂还好吗?\r\n");
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//输入
private static void in(){
File file =new File("E:\\java\\简单案例\\123.txt");
try {
Reader in = new FileReader(file);
char[] cs = new char[1];
int len = -1;
StringBuilder buffer = new StringBuilder();
while ((len=in.read(cs))!=-1){
buffer.append(cs,0,len);
}
in.close();
System.out.println(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、字节字符的转换流
转换流,可以将一个字节流转换为字符流,也可以将一个字符流转换成字节流;
- OutputStreamWriter: 可以将输出的字符流转换成字节流的输出形式
- InputStreamReader :将输入的字节流转换为字符流的字符流输入形式
public class ChangeStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
InputStream in = new FileInputStream("E:\\java\\简单案例\\123.txt");
OutputStream out = new FileOutputStream("E:\\java\\简单案例\\123.txt",true);
Writer(out);
read(in);
}
private static void read(InputStream in){
Reader reader =new InputStreamReader(in, Charset.defaultCharset());
char[] cs = new char[1024];
int len = -1;
try {
while ((len=reader.read(cs))!=-1);
{
System.out.println(new String(cs));
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void Writer(OutputStream out){
try {
Writer writer = new OutputStreamWriter(out,Charset.defaultCharset());
writer.write("不好的话换我上奥!!!");
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5、缓冲流
使用缓冲流的好处:能够更高效的读写信息,原理四将数据先缓冲起来,然后一起写入或者读取出来。 实现更高效的读取和写入操作;
解决在写入文件操作时,频繁的操作文件所带来的性能降低;
-
字节缓冲流
- BufferedInputStream : 为另一个输入流添加一些功能,在创建BufferedInputStream时,会创建一个内部缓冲区数组,用于缓冲数据;
- BufferedOutputStream : 通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
public class BufferStreamDemo {
public static void main(String[] args) {
// Write();
Read();
}
private static void Write(){
try {
OutputStream out = new FileOutputStream(“E:\java\简单案例\123.txt”,true);
BufferedOutputStream aos = new BufferedOutputStream(out);
String info = “我在家里学java”;
aos.write(info.getBytes());
aos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void Read(){
try {
InputStream in = new FileInputStream(“E:\java\简单案例\123.txt”);
BufferedInputStream bas = new BufferedInputStream(in);
byte[] bytes = new byte[1024];
int len = -1 ;
while ((len=bas.read(bytes))!=-1);{
System.out.println(new String(bytes));
}
bas.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
* 字符缓冲流
* BufferedReader : 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
```java
private static void Read(){
try {
InputStream in = new FileInputStream("E:\\java\\简单案例\\123.txt");
//为字符流提供缓冲,已达到高速读取的目的
BufferedInputStream bas = new BufferedInputStream(in);
byte[] bytes = new byte[1024];
int len;
while ((len=bas.read(bytes))!=-1);{
System.out.println(new String(bytes));
}
bas.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
- BufferedWriter : 将文本写入字符流输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
private static void CharWriter(){
File file = new File("E:\\java\\简单案例\\123.txt");
try {
Writer writer = new FileWriter(file);
//为字符流提供缓存,提高写入速率
BufferedWriter bw =new BufferedWriter(writer);
bw.write("你在监狱还好吗?");
bw.flush();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
6、打印流
打印流的主要功能就是用于输出,可以很方便地进行输出,在整个IO包中打印流分为两种类型:
字节打印流:PrintStream (增加输出功能)
private static void BytePrint(){
File file = new File("E:\\java\\简单案例\\123.txt");
try {
OutputStream out = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(out);
//打印流,增加输出的便利性
PrintStream ps = new PrintStream(bos);
ps.println("干你娘地别说话!!");
ps.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
字符打印流:PrintWriter ()
private static void CharPrint(){
File file = new File("E:\\java\\简单案例\\123.txt");
try {
Writer out = new FileWriter(file,true);
BufferedWriter bos = new BufferedWriter(out);
//打印流,增加输出的便利性
PrintWriter ps = new PrintWriter(bos);
ps.println("嘴长我身上我tm就得说!!");
ps.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
7、对象流和序列化
对象流的两个类:
-
ObjectOutputStream 将java对象的基本数据类型与图像写入OutputStream ;
-
ObjectInputStream 对以前使用ObjectOutputStream写入的基本类型数据和对象进行反序列化;
-
//如果一个类创建的对象,需要被序列化,该类必须实现一个Serializable接口 //Serializable 是一个标记接口,没有任何定义,为了告诉jvm该类可被序列化 //什么时候对象需要被序列化呢? //1、把文件保存到文件中(存储在物理介质中) //2、对象需要在网络上传输
序列化一组对象:
- 在序列化操作中,同时序列化多个对象时,反序列化也必须按顺序操作;
- 序列化一组对象可采用,对象数组的形式,因为对象数组可以向Object进行转型操作;
transient关键字:
如果用transient声明一个实例变量,当对象存储时,它的值不需要维持(在序列化中被忽略的);
8、字节数组流(基于内存操作)
-
ByteArrayinputStream
包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪read方法要提供的下一个字节。关闭ByteArrayinputStream 无效。此类中的方法在关闭此流后仍可调用,而不会产生任何IOException;
-
ByteArrayOutputStream
此类实现了一个输出流,其中的数据被写入一个byte数组。缓冲区会随着数据的不断写入而自动增长;可使用 toString ()获得数据;关闭ByteArrayOutputStream 无效;此类中的方法在关闭此流后仍可调用,而不会产生任何IOException;
public class ByteArrayStreamDemo {
public static void main(String[] args) {
byteArray();
}
private static void byteArray(){
String s = "i03232230lo02vle2334Y20O34324U";
ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int curr=-1; //每次读取的字节
while((curr=bais.read())!=-1){
if(curr>=65&&curr<=90 || curr>=97&&curr<=122){
baos.write(curr);
}
}
System.out.println(baos.toString());
}
}
9、数据流
- DataInputStream :数据输入流允许程序以与机器无关方式从底层输入流中读取基本java数据类型;应用程序可以使用数据输出流写入稍后由数据输入流读取的数据;DataInputStream对于多线程访问不一定是安全的。线程安全是可选的,它由此类方法的使用者负责。
private static void write(){
File file = new File("E:\\java\\简单案例\\test.bat");
try {
OutputStream out = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(out);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(10);//写入四个字节
dos.writeByte(1);//写入一个字节
dos.writeUTF("爱你");
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
- DataOutputStream:数据输出流允许应用程序以适当方式将基本java数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。
private static void read(){
File file = new File("E:\\java\\简单案例\\test.bat");
try {
InputStream in = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(in);
DataInputStream dis = new DataInputStream(bis);
int sum = dis.readInt();
byte b = dis.readByte();
String s = dis.readUTF();
System.out.println(sum+","+b+","+s);
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
-
案例:文件分割与合并
- 模拟压缩软件分割文件功能
public class FileDivisionMergeDemo { private static void Division(File targetFile, long cutSize){ if(targetFile==null) return; int num = targetFile.length() % cutSize == 0 ? (int)(targetFile.length() / cutSize) : (int)(targetFile.length() / cutSize +1); try { //构建一个文件输入流 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(targetFile)); BufferedOutputStream bos = null; byte[] bytes = null; //每次读取的字节数 int len = -1; int count = 0; //循环次数等于生成文件数量 for (int i = 0; i < num; i++) { bos = new BufferedOutputStream(new FileOutputStream( new File("E:\\java\\相关书籍\\division\\"+"temp_"+(i+1)+"_"+targetFile.getName()))); if(cutSize <= 1024){ bytes = new byte[(int)cutSize]; count = 1; }else { bytes = new byte[1024]; count = (int)cutSize / 1024; } while (count>0 && (len = bis.read(bytes))!=-1){ bos.write(bytes,0,len); bos.flush(); count--; } //计算余数 if(cutSize % 1024 !=0){ bytes = new byte[(int)cutSize % 1024]; len = bis.read(bytes); bos.write(bytes,0,len); bos.flush(); bos.close(); } } bis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { File file = new File("E:\\java\\相关书籍\\Java编程思想.zip"); Division(file,1024*1024); } }
10、合并流、字符串流、管道流
-
合并流
-
SequenceInputStream :表示其他输入流的逻辑串联;它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,知道到达包含的最后一个输入流的文件末尾为止。
public class FileDivisionMergeDemo { private static void Merge(Enumeration<InputStream> em){ //构造一个合并流 SequenceInputStream sis = new SequenceInputStream(em); try { BufferedOutputStream bos =new BufferedOutputStream(new FileOutputStream("E:\\java\\相关书籍\\division\\Merge_Java编程思想第五版.mobi")); byte[] bytes = new byte[1024]; int len = -1; while ((len=sis.read(bytes))!=-1){ bos.write(bytes,0,len); bos.flush(); } bos.close(); sis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // private static void Division(File targetFile, long cutSize){ // if(targetFile==null) // return; // int num = targetFile.length() % cutSize == 0 ? // (int)(targetFile.length() / cutSize) : // (int)(targetFile.length() / cutSize +1); // try { // //构建一个文件输入流 // BufferedInputStream bis = new BufferedInputStream(new FileInputStream(targetFile)); // BufferedOutputStream bos = null; // // byte[] bytes = null; //每次读取的字节数 // int len = -1; // int count = 0; // // //循环次数等于生成文件数量 // for (int i = 0; i < num; i++) { // bos = new BufferedOutputStream(new FileOutputStream( // new File("E:\\java\\相关书籍\\division\\"+"temp_"+(i+1)+"_"+targetFile.getName()))); // if(cutSize <= 1024){ // bytes = new byte[(int)cutSize]; // count = 1; // }else { // bytes = new byte[1024]; // count = (int)cutSize / 1024; // } // while (count>0 && (len = bis.read(bytes))!=-1){ // bos.write(bytes,0,len); // bos.flush(); // count--; // } // //计算余数 // if(cutSize % 1024 !=0){ // bytes = new byte[(int)cutSize % 1024]; // len = bis.read(bytes); // bos.write(bytes,0,len); // bos.flush(); // bos.close(); // } // } // bis.close(); // // } catch (FileNotFoundException e) { // e.printStackTrace(); // } catch (IOException e) { // e.printStackTrace(); // } // } public static void main(String[] args) { // File file = new File("E:\\java\\相关书籍\\Java编程思想.zip"); // Division(file,1024*1024); try { InputStream in1 =new FileInputStream(new File("E:\\java\\相关书籍\\division\\temp_1_Java编程思想第五版.mobi")); InputStream in2 =new FileInputStream(new File("E:\\java\\相关书籍\\division\\temp_2_Java编程思想第五版.mobi")); //集合工具类,内部使用了数组 Vector<InputStream> v = new Vector<InputStream>(); v.add(in1); v.add(in2); Enumeration<InputStream> em = v.elements(); Merge(em); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
-
-
字符串流
- StringReader :其源为一个字符串的字符流
public static void main(String[] args) { StringReader(); } //以一个字符串为数据流,来构造一个字符流 private static void StringReader(){ String info = "you are my favorite fruit"; StringReader sr = new StringReader(info); //流标记器 StreamTokenizer st = new StreamTokenizer(sr); int count = 0; while (st.ttype != StreamTokenizer.TT_EOF){ try { if(st.nextToken()==StreamTokenizer.TT_WORD){ count++; } } catch (IOException e) { e.printStackTrace(); } } sr.close(); System.out.println("count="+count); }
- StringWriter :一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串;关闭StringWriter无效,此类中的方法在关闭该流后仍可被调用,而不会产生任何IOException;
-
管道流
- 管道输入流应该连接到管道输出流,管道输入流提供要写入管道输出流的所有数据。通常,数据由某个线程从PipedInputStream 对象读取,并由其他线程将其写入到相应PipedOutputStream中;不建议对这两个对象尝试使用单线程,因为这样可能死锁线程;管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。
11、Properties文件操作
Properties(java.util.Propertoes):主要用于读取java配置文件,配置文件中很多变量是经常改变的,这样做也是为了方便用户,让用户能够脱离程序本身去修改相关的变量设置;
它提供了几个主要的方法:
-
getProperty(String key)
用指定的键在此属性列表中搜索属性,也就是通过参数key,得到key所对应的value;
-
load(InputStream inStream)
从输入流中读取属性列表(键和元素对);通过对指定的文件(比如下面的“config.properties”文件)进行装载来获取该文件中的所有键值对;以供getProperty搜索;
//读操作
public class PropertiesDemo {
private static String version="";
private static String username="";
private static String password="";
public static void main(String[] args) {
readProperties();
System.out.println(version);
System.out.println(username);
System.out.println(password);
}
private static void readProperties(){
Properties pt = new Properties();
try {
InputStream in = new FileInputStream("E:\\java\\ThreadTest\\src\\com\\test\\iodemo\\config.properties");
//将数据存到properties中
pt.load(in);
//从properties中获取数据
version=pt.getProperty("app.version");
username=pt.getProperty("username");
password=pt.getProperty("password");
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
-
setProperty(String key,String value)
调用Hashtable的方法put,通过调用基类的put方法来设置键值对;
-
store(OutputStream out, String comment)
以适合使用load方法加载到Peoperties表中的格式,将此Properties表中的属性(键和元素对)写入输出流;与load方法相反,该方法将键值对写入到指定文件中去;
//写操作
private static void writeProperties(String version,String username,String password){
Properties pt = new Properties();
pt.put("app.version",version);
pt.put("username",username);
pt.put("password",password);
try {
OutputStream out = new FileOutputStream("config.properties");
//写文件
pt.store(out,"update");
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
-
clear()
清除所有装载的键值对,该方法在基类中;
12、 文件压缩与解压缩
java中实现zip的压缩与解压缩
-
ZipOutputStream
实现文件的压缩;
-
ZipOutputStream(OutputStream out)
创建新的zip输出流;
-
void putNextEntry(ZipEntry e)
开始写入新的Zip文件条目并将流定位到条目数据的开始处;
-
ZipEntry( String name)
使用指定名称 创建新的ZIP条目;
//压缩文件
public class CompressionAndDeDemo {
public static void main(String[] args) {
compression("E:\\过去杂事文档\\学生科.zip",new File("E:\\学生科"));
}
private static void compression(String zipFileName, File targetFile){
System.out.println("压缩中");
try {
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
BufferedOutputStream bos = new BufferedOutputStream(out);
Zip(out,targetFile,targetFile.getName(),bos);
bos.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("压缩成功!!!");
}
private static void Zip(ZipOutputStream zOut,File targetFile,
String name,BufferedOutputStream bos) throws IOException {
//如果是个目录
if(targetFile.isDirectory()){
File[] files = targetFile.listFiles();
//如果是空目录
if(files.length==0){
zOut.putNextEntry(new ZipEntry(name+"/"));
}
for(File f:files){
//递归 处理
Zip(zOut,f,name+"/"+f.getName(),bos);
}
}
else {
zOut.putNextEntry(new ZipEntry(name));
InputStream in = new FileInputStream(targetFile);
BufferedInputStream bis = new BufferedInputStream(in);
byte[] bytes =new byte[1024];
int len =-1;
while ((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bis.close();
}
}
}
-
ZipInputStream
实现文件的解压
-
ZipInputStream(InputStream out)
创建新的ZIP输入流
-
ZipEntry putNextEntry()
读取下一个zip文件条目并将流定位到该条目数据的开始处
//解压文件
private static void decompression(String targetFileName, String parent){
try {
//构建解压输入流
ZipInputStream zIn =new ZipInputStream(new FileInputStream(targetFileName));
ZipEntry entry = null;
File file = null;
while((entry=zIn.getNextEntry())!=null && !entry.isDirectory()){
file = new File(parent,entry.getName());
if(!file.exists()){
new File(file.getParent()).mkdir();//创建此文件的上级文件
}
OutputStream out = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(out);
byte[] bytes = new byte[1024];
int len =-1;
while((len=zIn.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.close();
System.out.println(file.getAbsolutePath()+"解压成功!!");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
13、IO常用类体系
14、装饰者设计模式
-
意图
动态地给一个对象添加一些额外的职责,就增加功能来说,Decorator模式相比生成子类更为灵活,该模式以对客户端透明的方式扩展对象的功能;
-
使用环境
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加指责;
- 处理那些可以撤销的职责;
- 当不能采用生成子类的方法进行扩充时,一种情况是:可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类的数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
-
Component(被装饰对象基类)
定义对象的接口,可以给这些对象动态增加职责;
-
ConcreteComponent(具体被装饰对象)
定义具体的对象,Decorator可以给它增加额外的职责;
-
Decorator(装饰者抽象类)
维护指向Component实例的应用,定义与Component一致的接口;
-
ConcreteDecorator(具体装饰者)
具体的装饰对象,给内部持有的具体被装饰对象增加具体的职责;
15、常见的字符编码
在计算机世界中,任何文字都是以编码形式存在的;
常见的编码有:
-
iso8859-1:
编码属于单字节编码,最多只能表示0-255的字符范围,主要在英文上应用;
-
GBK/GB2312:
中文的国际编码,专门用来表示汉字,是双字节编码;
-
unicode
java中使用此编码方式,也是最标准的一种编码,是使用十六进制表示的编码;但此编码不兼容iso8859-1编码;
-
UTF
由于unicode不支持iso8859-1编码,而且容易占用更多空间,而且对于英文字母也需要使用两个字节编码,这样使用unicode不便于传输和储存,每个字符的长度从1-6个字节不等,一般在中文网页中使用此编码,因此这样可以节省空间。
造成乱码的根本原因
- 程序使用的编码与本机编码不统一;
- 在网络中,客户端与服务端不统一;
16、New IO
**目的:**让java程序员可以实现I/O而无需编写自定义的本机代码;NIO将最耗时的I/O操作(即填充和提取缓冲区)转移回操作系统,因而可以极大地提高速度;
流与块的比较
-
原来的I/O库(在java.io.*中)与NIO最重要的区别是数据打包和传输的方式,原来的I/O以流的方式处理数据,二NIO以块方式处理数据;
-
面向流的I/O系统一次一个字节地处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据,面向流的I/O通常比较慢;
-
一个面向块的I/O系统以块的形式处理数据,每一个操作都在一步中产生或者消费一个数据块,按块处理数据比按流处理要快得多,但是面向块的I/O缺少一些面向流的I/O所具有的优雅性和简单性;
缓冲区
-
在NIO库中,所有数据都是用缓冲区处理的,在读取数据时,直接读到缓冲区中;在写入数据时,它是写入缓冲区中的,任何时候访问NIO中的数据,都是将它放到缓冲区中;
-
缓冲区其实是一个数组,通常是一个字节数组,但是也可以使用其他种类的数据;一个缓冲区也并是一个数组,缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读写、进程。
缓冲区类型
最常用的缓冲区类型是ByteBuffer,一个ByteBuffer可以在其底层字节数组上进行get/set操作(即字节的获取和设置);
对应每一种java类型都有一种缓冲区:
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
通道:Channel
-
Channel 是一个对象,可以通过它读取和写入数据;拿NIO与原来的I/O做个比较,通道就像是流;
-
你不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节;
public static void main(String[] args) throws IOException {
copyFile();
}
//文件通道方式实现复制文件
private static void copyFile() throws IOException {
//创建一个输入文件的通道
FileChannel fcIn = new FileInputStream("E:\\美食网\\法国.jpg").getChannel();
//创建一个输出文件的通道
FileChannel fcOut = new FileOutputStream("E:\\美食网\\法国1.jpg").getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
while((fcIn.read(buf))!=-1){
buf.flip();
fcOut.write(buf);
buf.clear();
}
fcIn.close();
fcOut.close();
System.out.println("copy successful!!");
}
Path接口
- Path表示的是一个目录名序列,其后还可以跟一个文件名,路径中第一个部件是根部件时就是绝对路径,例如:、或者C:\,而允许访问的根部件取决于文件系统;
- 以根部件开始的路径是绝对路径,否则就是相对路径;
- 静态的Paths.get方法接受一个或多个字符串,字符串之间自动使用默认文件系统的路径分隔符连接其拉力(Unix是/,Window是),这就解决了跨平台的问题,接着解析连接起来的结果,如果不是合法路径就抛出InvalidPathException异常,否则就返回一个Path对象;
File工具类
- 读写文件
static path write(path path,byte[] bytes,OpenOption...options) //写入文件
static byte[] readAllBytes(Path path) //读取文件中的所有字节
- 复制、剪切、删除
static path copy(Path source, Path target,CopyOption...options)
static path move(Path source, Path target,CopyOption...options)
static void delete(Path path)
static boolean deleteIfExists(Path path)
//案例
public static void main(String[] args) throws IOException {
File file = new File("E:\\美食网\\法国.jpg");
Path p1 = Paths.get("E:\\美食网","法国.jpg");
System.out.println(p1);
Path p2 = file.toPath();
System.out.println(p2);
Path p3 = FileSystems.getDefault().getPath("E:\\美食网\\法国.jpg");
//File工具类
Path p4 = Paths.get("E:\\美食网","法国.txt");
String info ="上厕所记得关门啊!!!";
try {
//写操作
Files.write(p4,info.getBytes("UTF-8"),StandardOpenOption.APPEND);
//读取操作
byte[] bytes = Files.readAllBytes(p4);
System.out.println(new String(bytes));
} catch (IOException e) {
e.printStackTrace();
}
//复制文件(存在即替换)
Files.copy(p3,Paths.get("E:\\美食网\\中国美食\\法国.jpg"),StandardCopyOption.REPLACE_EXISTING);
//移动文件
Files.move(p3,Paths.get("E:\\美食网\\中国美食\\法国.jpg"),StandardCopyOption.REPLACE_EXISTING);
//删除文件
Files.delete(Paths.get("E:\\美食网\\中国美食\\法国.jpg"));
}
- 创建文件和目录
Files.createDirectory(Paths.get("E:\\美食网\\中国美食\\荞凉粉"));
//创建文件
Files.createFile(Paths.get("E:\\美食网\\中国美食\\荞凉粉\\荞凉粉.jpg"));
//添加前、后缀创建临时文件或临时目录
Path newPath = Files.createTempFile(dir, prefix, suffix);
Path newPath = Files.createTempDirectory(dir, prefix);