FILE AND IO

19 篇文章 0 订阅
2 篇文章 0 订阅

声明:学基础,在校学生,本文所有内容来自书本和视频,然后通过自己的理解和筛选编写而来,如有理解不到位的写得不到位的地方,欢迎评论指错!!!(仅做学习交流)
笔者:Fhvk
微信:WindowsC-

java.io.File类

  • File更应该叫做一个路径;文件路径或文件夹路径;路径分为绝对路径和相对路径;

  • 构造方法
    File(String pathname); 根据一个路径得到一个File对象;就是将路径封装成一个对象
    File(String parent,String child);根据一个目录和一个子文件夹/目录得到File对象;
    File(File parent.String child);根据一个父File对象和一个子文件/目录得到File对象;

  • 注意:

File file = new File("C:\demo\d.txt");  //错误的
File file = new File("C:\\demo\\d.txt"); //正确的,要转义
但开发中不推荐这样写,因为各个操作系统路径写法不同;
windows : " \"   反
linux:" / " 正
开发中如何解决:使用File类中常量separator获取当前系统的路径符
File file = new File("C:" + File.separator + "demo"+ File.separator +"d.txt");
  • 创建功能
    public boolean createNewFile();//创建文件,如果存在就不创建;
    public boolean mkdir();//创建文件夹,如果存在就不创建了;
    public boolean mkdir();//创建多级文件夹;
public class DemoFileMethod {
	public static void main(String[] agrs) {
		//如果没加盘符就是默认当前项下,你要创建到别的路径可以写全
		File file1 = new File("aaa.txt");
		//创建文件
		System.out.println(file1.createNewFile()); //返回false,true
		//其它方法一样写法    
	}
}
  • 重命名和删除功能
    public boolean renameTo(File dest);//把文件重命名为指定路径
    注意:如果路径相同,就是改名;如果路径不相同,就是改名并剪切;
    public boolean delete();删除文件或者文件夹
    注意:删除不走回收站;要删除一个文件夹,请注意该文件夹内不能有其它文件或文件夹;否则无法删除;

  • 判断功能
    public boolean isDirectory();判断是否是文件夹
    public boolean isFile();判断是否是文件
    public boolean exists();判断文件是否存在;
    public boolean setReadable(boolean readable); 设置可读属性
    public boolean setWritable(boolean writable);设置可写属性
    public boolean canRead();判断是否可读;
    public boolean canWrite();判断是否可写;

  • 获取功能
    public String getAbsolutePath();//获取绝对路径
    public String getPath();//获取路径就是构造方法里的路径
    public String getName();//获取名称
    public long length();获取长度。字节数
    public long lastModified();获取最后一次修改的时间,毫秒值;
    public String[] list();获取指定目录下所有文件或文件夹的名称数组;
    public File[] listFiles();获取指定目录下所有的文件或文件夹的File数组
    在这里插入图片描述
    运行结果:
    在这里插入图片描述

案例输出指定目录下指定后缀的文件名

/**
 *	判断ddd文件夹下是否有后缀名为.txt的文件如果有就输出该文件名
 */
 public class Test {
	public static void main(String[] agrs) {
		File dir = new File("ddd");
		System.out.println("该文件夹是否存在 : " + dir.isDirectory());
		File[] arr = dir.listFiles();
		printFileName(arr);
	}
	public static void printFileName(File[] file) {
		for(File file1 : file) {
			//endsWith()方法在String类中判断是否为传入字符串结束;
			if(file1.isFile() && file1.getName().endsWith(".txt")) {
				System.out.println(file1.getName());
			}
			if(file1.isDirectory) {
				printFileName(file1.listFiles());
			}
		}
	}
}

过滤器(文件名称过滤器)

如果使用

public class Demo {
	public static void main(String[] agrs) {
		File dir = new File("ddd");
		//通过要实现FilenameFiler接口并重写accept()方法,使用匿名内部类
		String[] name = dir.list(new FilenameFiler() {
			public boolean accept(File dir,String name) {
				File file  = new File(dir,name);
				return file.isFile() && file.getName.endsWith("txt");
			}
		});
	}
}

public File[] listFiles(FilenameFiler filter); //也可以

  • 源码
public list(FilenameFiler filter) {
	String names[] = list();   //也就是要操作的文件夹
	//获取该文件夹下所有的名称后,如果看于null、如果过滤器为null,就返回null
	if((names == null) || (filter == null)) {
			return names;
	}
	List<String> v = new ArrayList<>();
	for(int i = 0; i < names.length; i++) {
		//如果为true就添加到集合中
		if(filter.accept(this,names[i])) {
			v.add(name[i]);
		}
		return v.toArray(new String[v.size()]);//将集合转为String[];
	}
}

IO流的概述及其分类

  • 概念:IO流用来处理设备之间数据的传输;Java对数据的操作是通过流;Java操作流的类在IO包中;流按流向分为:1、输入流 2、输出流;

  • 流按操作类型分为:
    1、字节流:字节流可以操作任何数据;因为在计算中所有数据都以字节的形式存储的;
    2、字符流:字符流只能操作纯字符的数据;比较方便;

  • IO流常用类
    1、字节流的抽象父类
    InputStream(输入流)
    OutputStream(输出流)
    2、字符流
    Reader(输入流)
    Writer(输出流)

  • IO程序书写
    使用前:导入IO包中的类
    使用中:进行IO异常处理
    使用后:释放资源

FileInputStream(文件输入流)

  • 使用FileInputStream读取文件夹数据
public class Demo {
	public static void main(String[] agrs) throws IOException{
		FileInputStream fis = new FileInputStream("ddd.txt");
		int b = 0;
		while((b = fis.read()) != -1) {
			System.out.print((char)b);
		}
		fis.close();  //关闭流
	}
}
  • 为什么read()方法的返回的是一个int ,明明是一个字节一个字节读,而int是4个字节;

答:因为字节输入流可以操作任意类型的文件,比如:视频、音频、图片等,这些文件在计算机上都是以二进制形式存储的,如果每次读返回的都是byte,有可能在读到中间的时候遇到11111111,那么这11111111是byte的-1,我们程序遇到-1就停止读取了,所以在读取的时候用int类型接收;如果11111111会在前面补上28个0,补足4个字节;那么byte的-1就等于int的255,这样就保证完整性;而结束标记也是int的-1;

FileOutputStream(文件输出流)

  • 使用FileOutputStream写入数据
public class Demo {
	public static void main(String[] agrs) throws IOException{
		//如果不加true,就不是追加形式添加,它默认会清空原有数据,重新写,而加了true就是追加;不清空;
		FileOutputStream fos = new FileOutputStream("xxx.txt",true);
	}
}
  • 注意:不管是FileInputStream还是OutputStream都是一个字节一个字节操作的

文件的拷贝

  • 使用FileInputStream+FileOutputStream
  • 第一种:效率太低
public class Demo {
	public static void main(String[] agrs) throws IOException{
		//创建输入流;读取数据
		FileInputStream fis = new FileInputStream("xxx.mp3");
		FileOutputStream fos = new FileOutputStream("copy.mp3");
		int b = 0;
		//当读到-1就代表读完了到文件未尾,跳出循环;
		while((b = fis.read()) != -1) {
			//一个字节一个字节写到copy中
			fos.write(b);
		}
		System.out.println("拷贝成功!");
		//关闭流
		fis.close():
		fos.close();
	}
}
  • 但这样写效率很低,如果这个文件有几十M或几百M甚至更大,会非常慢,一个字节读一个字节写;
  • 第二种拷贝,如下
    int available();获取该文件的字节大小;
	//假设这个文件有10个G
public class Demo {
	public static void main(String[] agrs) throws IOException{
		FileInputStream fis = new FileInputStream("xxx.mp3");
		FileOutputStream fos = new FileOutputStream("copy.mp3");
		byte[] arr = new byte[fis.available()];  //该方法获取文件字节长度
		fis.read(arr);  //一次获取10个G
		fis.write(arr); //一次写10个G
		fis.close();
		fos.close();
	}
}
  • 第二种拷贝也不建议使用,有可能会内存溢出,因为如果文件内存过大,一次读写会出现问题

  • 第三种(定义小数组,标准)

public class Demo {
	public static void main(String[] agrs) throws IOException{
		//创建输入输出流
		FileInputStream fis = new FileInputStream("xxx.txt");
		FileOutputStream fos = new FileOutputStream("copy.txt");
		//定义小数组
		byte[] arr = new byte[1024]; //一次保存1024个字节;数组大小定义为1024的整数倍;
		int len; //保存有效字节个数
		//一次读取1024个字节,返回有效字节个数,如果有效字节个数为-1,说明读到未尾了;
		while((len = fis.read(arr)) != -1) {
			//写到文件中
			fos.write(arr,0,len);
		}
	}
}

BufferedInputStream和BufferedOutputStream(缓冲)

  • 缓冲思想
    字节流一次读写一个数组的速度明显比读写一个字节的速度快很多;
    这是加入了数组这样的缓冲效果,JAVA本就设计的时候,也是考虑到了这样的设计思想(装饰设计模式),所以提拱了字节流缓冲区流

  • BufferedInputStream
    BufferedInputStream内置了一个缓冲区(数组)
    从BufferedInputStream读取数据时,会一次性从文件中读取8192个字节;在在缓冲区中,然后一个一个返回给程序,直到8192返回完,再重新读取8192个;

  • BufferedOutputStream
    BuuferedOutputStream也内置了一个数组;
    程序向流中写数据时,不会直接写到文件,先一个一个写到缓冲区,直到缓冲区写满8192个;就一次写到文件中;
    在这里插入图片描述

public class Demo_Buffered {
	pbulic static void main(String[] agrs) {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("xxx.txt"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.txt"));
		int b = 0;
		while((b = bis.read) != -1) {
			bos.write(b);
		}
		bis.close();
		bos.close();
	}
}
  • 小数组和Buffered哪个更快?如果数组都是8192个大小,那么小数组要快一点,因为Buffered是两个数组,而小数组就只有一个数组;
  • flush()和close()方法的区别
    flush()方法:用来刷新缓冲区,刷完之后还可以继续写出;
    close()方法:用来关闭流释放资源的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭前刷新缓冲区,关闭后不能再写出;

字节流读写中文

1、字节流读取中文的问题:字节在读取中文的时候有时候会读取半个中文,造成乱码;
2、字节流写出中文的问题:字节流直接操作的是字节,所以写出中文必须将字符串转成字节数组;

//写数据
public class Demo {
	public static void main(String[] agrs) {
		FileOutputStream fos = new FileOutputStream("yyy.txt");
		fos.write("你好".getBytes());   //转字节数组
		fos.close();
	}
}

标准异常处理代码(jdk1.6&&jdk1.7)

  • jdk1.6前
public class Demo {
	public static void main(String[] agrs) throws IOException{
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream("yyy.txt");
			fos = new FileOutputStream("copy.txt");
			byte[] arr = new byte[1024];
			int len = 0;
			while((len = fis.read(arr)) != -1) {
				fos.write(arr,0,len);
			}
		} finally {
			try {
				if(fis != null) {
					fis.close();
				}
			} finally {
				if(fos != null) {
					fos.close();
				}
			}
		}
	}
}
  • jdk1.7
/**
 *	jdk1.7
 *不用你调用close()方法,自动调用,因为try里面的类都间接的实现了AutoCloseable接口
 */

public class Demo {
	public static void main(String[] agrs) thorws IOException{
		try(
			FileInputStream fis = new FileInputStream("yyy.txt");
			FIleOutputStream fos = new FileOutputStream("copy.txt");
		) {
			byte[] arr = new byte[1024];
			int len = 0;
			while((len = fis.read(arr)) != -1) {
				fos.write(arr,0,len);
			} 
		}
	}
}

图片加密

  • 就是重新复制一份照片,让其打不开,想打开通过密码读取出来
  • 原理就是异或一个数,这个数就是密码;因一个数异或一个数两次就是其本身;
    实现
//加密
public class Demo {
	public static void main(String[] agrs) throws IOException{
		BufferedInputStream bis = new BuffereedInputStream(new FileInputStream("cd.jpg"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
		int b = 0;
		while((b = bis.read()) != -1) {
			bos.read(b ^ 123);//异或 加密,这样写进去会乱码,达到加密效果
		}
		bis.close():
		bos.close();
	}
}

//解密
public class Demo {
	public static void main(String[] agrs) throws IOException{
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("copy.jpg"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy1.jpg"));
		int b = 0;
		while((b = bis.read()) != -1) {
			bos.write(b ^ 123); //解密 
		}
		bis.close();
		bos.close();
	}
}

在控制台输入文件路径,该文件拷贝到当前项目下

/**
 *1、定义一个方法获取键盘录入文件路径,并进行判断,如果是文件就返回,不是就给提示无限输入;
 *2、在主方法调用
 *3、读写操作
 public class Test throws IOException{  
	public static void main(String[] agrs) {
		File file = getFIle()
		FileInputStream fis = new FileInputStream(file);
		FileOutputStream fos = new FileOutputStream(file.getName()); //名字可以不变
		byte[] arr = byte[1024];   //使用小数组
		int len;
		while((len = fis.read(arr)) != -1) {
			fos.write(arr,0,len);
		}
		fis.close();
		fos.close();
	}	
	public static File getFile() {
		//键盘录入对象
		Scanner sc = new Scanner(System.in);
		//	给出提示
		System.out.println("请输入正确的路径: ");
		while(true) {
			String line = sc.nextLine();
			File file = new File(line);
			if(!file.exists()) {
				System.out.println("该路径不存在,请重新输入:");
			}else if(file.isDirectory()) {
				System.out.println("该文件是文件夹,请重新录入:");
			} else {
				return file;
			}
		}
	}
}

录入数据拷贝到文件

/**
 *1、创建录入对象
 *2、创建输出流对象,关联text.txt文件
 *3、定义无限循环
 *4、遇到quit退出
 *5、如果不是quit就写出
 *6、关流
public  class Test {
	public static void main(String[] agrs) {
		//1、创建录入对象
		Scanner sc  = new Scanner(System.in);
		//2、创建输出流对象,关联text.txt文件
		BufferedOutputStream bos = new BufferedOutputStream(new FIleOutputStream("text.txt"));
		System.out.println("请输入数据:");
		//3、定义无限循环
		while(true) {
			String line = sc.nextLine();
			//4、遇到quit退出
			if("quit".equals(line)) {
				break;
			}
			//5、如果不是quit就写出
			bos.write(line.getBytes());
			bos.write("\r\n".getBytes());
			System.out.println("可以继续录入:");
		}
		bos.close();
	}
}

字符流Reader&Writer

  • 字符流是什么?字符流是可以直接读取字符的IO流;字符流读取字符,就要先读取到字节数据,然后转为字符;如果要写出字符,需要把字符转为字节再写出;
  • 字符流是如果读取中文的?根据码表,比如遇到GBK码表,中文是两个字节,第一个字节为负数,所以读的时候,遇到负数,就同时读两个字节;
  • FileReader类的使用(父类是Reader)
public class Demo_FileReader {
	public static void main(String[] agrs) {
		FileReader fr = new FileReader("www.txt");
		int b = 0;
		while((b = fr.read()) != -1) {
			System.out.printl(char(b));
		}
		fr.close();
	}
}
  • FileWriter类的使用(父类是Writer)
public class Demo_FileWriter {
	public static void main(String[] agrs) {
		FileWriter fw = new FileWriter("copy.txt"); 
		fw.write("ssdadsa");
		fw.close();
	}
}
  • 字符流的拷贝
public class Demo {
	public static void main(String[] agrs) throws IOException{
		FileReader fr = new FileReader("qq.txt");
		FileWriter fw = new FileWriter("copy.txt");
		int b = 0 ;
		while((b = fr.read()) != -1) {
			fw.write(b);
		}
		fr.close();
		fw.close(); //看源码得知有一个2k的缓冲区,如果不关流,内容将一直在缓冲区中;close()有刷新的效率;
	}
}

什么情况下使用字符流

  • 字符流不用于文件的拷贝,因为效率没有字节流拷贝高;字符流每次读和写操作都要进行转换,而字节流没有任何转换;所以字节流效率比字符流高
  • 字符流常用于只读,或只写操作:1、只读的时候,不会出现读取1个字节,而导致中文乱码;2、只写时候,不用将字符通过getBytes()进行转换,字符流直接低层给你转换了;

字符流能不能拷贝非纯文本的文件(视频或音频等)

  • 很明显不行:因为在读的时候会将字节转换为字符,在读的过程中,可能找不到对应的字符;就会用?代替,写出的时候会将字符将成字节,如果是?,写到文件中就乱码了,导致文件损坏,而看不了了

小数组字符流

public class Demo {
	public static void main(String[] agrs) {
		FileReader fr = new FileReader("xxx.txt");
		FileWriter fw = new FileWroter("copy.txt");
		char[] arr = new char[1024 * 8];
		int len = 0;
		while((len fr.read(arr)) != -1) {
			fw.write(arr,0,len);
		}
		fr.close();
		fw.close();
	}
}

缓冲字符流

public class Demo {
	public static void main(String[] agrs) {
		BufferedReader br = new BufferedReader(new FileReader(""xxx.txt));
		BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
		int c = 0;
		while((c = br.read()) != -1) {
			bw.write(c);
		}
		br.close();
		bw.close();
	}
}

BufferedReader中readLine()方法

  • readLine()方法:用取读取一行数据;一行结束符是\r\n;文件结束符是null;

  • 读取的时候不会读取\r\n;

public class Demo {
	public static void main(String[] agrs) {
		BufferedReader br = new BufferedReader(new FileReader("qqq.txt"));
		String line = null; 
		while((line  = br.readLine()) != null) {
			System.out.println(line);
		}
		br.close();
	}
}

BufferedWriter中newLine()方法

  • newLine()方法:写入回车换行

  • newLIne()方法与\r\n的区别是:
    1、newLine():跨平台;
    2、\r\n只有win中有效

public class Demo {
	public static void main(String[] agrs) {
		BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
		bw.write("dsfdsfds");
		bw.newLine();  //代表回车换行
	}
}

文本反转

  • 注意事项:流晚开早关
public class Demo {
	public static void main(String[] agrs) {
		BufferedReader br = new BufferedReader(new FileReader("qq.txt"));
		ArrayList<String> list = new ArrayList<String>();
		String line = null;
		while((line = br.readLine()) != null) {
			list.add(line);
		}
		br.close();
		BufferedWriter bw = new BufferedWriter(new FileWriter("sd.txt"));
		for(int i = list.size() - 1; i >= 0; i--) {
			bw.write(list.get(i));
			bw.newLine();
		}
		bw.close();
	}
}

LineNumberReader(行号)

  • 是BufferedReader的子类,所以继承了readLine()方法;
  • 方法:getLineNumber()方法获取行号和setLineNumber()方法设置行号;
public class Demo {
	public static void main(String[] agrs) {
		LineNumberReader lnr = new LineNumberReader(new FileReader("aa.txt"));
		String line  = null;
		lnr.setLineNumber(100); // 从101开始设置
		while((line = lnr.readLine()) != null) {
			System.out.println(getLineNumber() + line);
		}
	}
}

装饰设计模式

  • 优点:藕合性不强;
public class Demo {
	HMStudent hs = new HMStudent(new Student());
	hs.code();
}

interface Coder {
	public void code();
}

class Student implements Coder {
	public void code() {
			System.out.println("javase");
			System.out.println("javaweb");
	}
}

//为什么不直接继承Student,然后直接重写code,就是为了降低偶合性,这样两个类完全是分离的;
class HMStudent implements Coder {
	private Student s;
	public HMStudent(Student s) {
		this.s = s;
	}
	public void code() {
		s.code();
		System.out.println("数据库");
		System.out.println("ssh");
	}
}

使用指定码表读写字符

  • FileReader是使用默认码表进行读取的,如果需要指定码表读取,请使用InputStreamReader(字节流,编码表);

  • FileWriter是使用默认码表进行写出的,如果需要指定码表写出。请使用OutputStreamWriter(字节流,编码表);

  • 注意:GBK中文占两个字节,UTF-8中文占3个字节;

public class Demo {
	public static void main(String[] agrs) {
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("xxx.txt"),"UTF-8"));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("copy.txt"),"UTF-8"));
		String line;
		while((line  = br.readLine()) != null) {
			bw.write(line);
			bw.newLine();
		}
		br.close();
		bw.close();
	}
}

转换流图解

在这里插入图片描述

获取文本上字符出现的次数

/**
 * 获取一个文本上每个字符出现的次数,将结果写在times.txt中
 * @author MAC
 *1、创建缓冲输入流对象 
 *2、创建TreeMap集合对象,增加排序的效果
 *3、将读到的字符存储到双列集合中,存的时候要判断,如果不包含这个键,就将键和1存储,如果包含了这个键,就给值 +1;
 *4、关闭输入流
 *5、创建输出流对象
 *6、遍历集合,将集合中的内容写到times.txt中
 *7、关闭流出流  
 */
public class Test11 {
	public static void main(String[] agrs) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("utf-8.txt"),"utf-8"));
		TreeMap<Character,Integer> tm = new TreeMap<>();
		int ch = 0;
		while((ch = br.read()) != -1) {
			tm.put((char)ch, !tm.containsKey((char)ch) ? 1 : tm.get((char)ch) + 1);   //三元运算符
		}
		br.close();
		BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
		for(Character key : tm.keySet()) {
			switch (key) {
			case '\r':
				bw.write("\\r" + " = " + tm.get(key));
				break;
			case '\n':
				bw.write("\\n" + " = " + tm.get(key));
				break;
			case '\t':
				bw.write("\\t" + " = " + tm.get(key));
				break;				
			default:
				bw.write(key + " = " + tm.get(key));
				break;
			}
			bw.newLine();
		}
		bw.close();
	}
}

试用版软件

  • 很多软件都是有试用次数的,使用完之后要收费,下面就是简单的实现方法.
public class Demo {
	public static void main(String[] agrs) throws IOException{
		BufferedReader br = new BufferedReader(new FileReader("qq.txt"));
		String line = br.readLine();  //读取一行数据
		br.close();    //
		int times = Integer.paseInt(line);
		if(times > 0) {
			System.out.println("您还有 " + times-- + "次试行机会!");
			FileWriter fw = new FileWriter("qq.txt");
			fw.write(times + "");   //以字符串形式写出去
			fw.close();
		}else {
			System.out.println("您的试用次数已使用完,请购买正版!");
		} 
	}
}

递归

  • 就是方法自己调用自己
  • 经典求阶乘
public class Demo {
	public static void main(String[] agrs) {
		System.out.println(fun(5));  //求5的阶乘 
	}
	public static int fun(int num) {
		if(num == 1) {
			return 1;
		} else {
			return num * fun(num - 1);
		}
	}
}

- 注意:递归的弊端:不能调用次数太多,容易造成栈内存溢出;好处就是不用知道调用多少次;

  • 构造方法是否可以递归调用? 不能!!!
  • 递归调用是否必须有返回值? 可以有也可以没有;比如说输出文件夹中所有的文件;

使用递归输入文件夹下所有.java的文件(文件夹中可能还有文件夹)

需求  : 从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件;
分析 :
通过自定义方法从键盘录入一个文件夹路径
1、如果输入路径非法,给出提示;
2、如果输入路径是文件路径,给出提示;
3、如果输入的是文件夹路径,直接return返回;

通过自定义方法打印出该文件夹下所有的.java文件
1、获取该文件夹下所有的文件和文件夹,存储在File数组中;
2、遍历该数组,对第一个文件和文件夹进行判断
3、如果是文件并且是.java的文件就直接打印其名称
4、如果是文件夹就递归调用该方法
public class Demo {
	public static void main(String[] agrs) {
		File dir = getDir();
		printJavaFile(dir);	}
	public static void printJavaFile(File dir) {
			File[] subFIles = dir.listFiles();
			for(File file : subFiles) {
				if(file.isFile() && file.getName().endsWith(".java")) {
					System.out.println(file.getName());
				} else if(file.isDirectory()) {
					printJavaFile(file);  //递归调用
				}
			}
	}
	//录入文件夹路径
	public static File getDir(File dir) {
		Scanner sc  = new Scanner(System.in);
		System.out.print("请输入文件夹路径 : ");
		while(true) {
			String line = sc.nextLine():
			File dir = new File(line);
			if(dir.exists()) {
				System.out.println("您录入的不是路径,请继续录入!");
			}else if(dir.isFile()) {
				System.out.println("您录入的是文件路径,请继续录入!");
			} else {
				System.out.println("录入成功!");
				return dir;
			}
		}
	}
}

序列流

  • SequenceInputStream:序列流, 我的理解是将两个输入流或者多个输入流打包成一个流读取;
public class Demo1_SequenceInpuStream {
	
	public static void main(String[] agrs) throws IOException{
		//Demo1();//没有使用序列流
		//Demo2();//两个输入流打包成序列流
		//Demo3(); //多个输入流打包成一个序列流
		
	}
	//SequenceInputStream(Enumeration);使用枚举,解决复用性,解决使用多个流打包
	private static void Demo3() throws FileNotFoundException, IOException {
		FileInputStream fis1 = new FileInputStream("a.txt");
		FileInputStream fis2 = new FileInputStream("b.txt");
		FileInputStream fis3 = new FileInputStream("c.txt");
		Vector<FileInputStream> v = new Vector<>();
		v.add(fis1);
		v.add(fis2);
		v.add(fis3);
		SequenceInputStream sis = new SequenceInputStream(v.elements());
		FileOutputStream fos = new FileOutputStream("copy.txt");
		int b = 0;
		while((b = sis.read()) != -1) {
			fos.write(b);
		}
		sis.close();
		fos.close();
	}
	//两个输入流打包成序列流,限制只能打包两个流
	private static void Demo2() throws FileNotFoundException, IOException {
		FileInputStream fis1 = new FileInputStream("a.txt");
		FileInputStream fis2 = new FileInputStream("b.txt");
		SequenceInputStream  sis = new SequenceInputStream(fis1,fis2);
		FileOutputStream fos = new FileOutputStream("copy.txt");
		int b = 0;
		while((b = sis.read()) != -1) {
			fos.write(b);
		}
		sis.close();  //sis在关闭流的时候,会将构造方法中传入流对象也都关闭;
		fos.close();
	}
	//没有使用序列流,复用性太差;
	private static void Demo1() throws FileNotFoundException, IOException {
		FileInputStream fs1 = new FileInputStream("a.txt");
		FileOutputStream fo = new FileOutputStream("copy.txt",true);
		int b = 0; 
		while((b = fs1.read()) != -1) {
			fo.write(b);
		}
		fs1.close();
		FileInputStream fs2 = new FileInputStream("b.txt");
		int c = 0;
		while((c = fs2.read()) != -1) {
			fo.write(c);
		}
		fs2.close();
		fo.close();
	}
}

内存输出流

  • 什么是内存输出流?该输出流可以向内存中写数据,把内存当成一个缓冲区,写出之后可以一次性获取所有数据;
  • 使用方法:
    -1、创建对象:new ByteArrayOutputStream();
    -2、写出数据:write(int ),write(byte[]);
    -3、获取数据:toByteArray():返回byte[]。 toString():直接返回String;
public class Demo {
	public static void main(String[] agrs) throws IOException{
		FileInputStream fis = new FileInputStream("aa.txt");
		//在内存中创建了可增长的内存数组
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] arr = new byte[1024];
		int len = 0;
		while((len = fis.read(arr)) != -1) {
			baos.write(arr,0,len);
		}
		//关闭输入流
		fis.close();
		//toString()方法获取数据
		System.out.println(baos.toString());   //toString()方法可以省略
		//toByteArray()方法获取数据
		byte[] data = baos.toByteArray();
		System.out.println(new String(data));
		baos.close(); //关闭无效,因为它不是流,它在底层创建了内存缓冲区数组,而不是连接了硬盘;它使用完会自动释放;不用关
	}
}
  • 案例
/*
 *定义一个文件输入流,调用read(byte[] arr)方法,将a.txt文件中的内容打印出来,(byte	数组大小限制为5)
 *分析:
 *1、read(byte[] arr)方法是字节流所以创建FileInputStream,关联a.txt;
 *2、创建字节数组,大小为5
 *3、创建内存输出流,将读到的数据写到内存输出流中;
 *4、然后直接打印
 */
 public class Demo {
	public static void main(String[] agrs) throws IOEexception{
		FileInputStream fis = new FileInputStream("a.txt");
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] arr = new byte[5];
		int len = 0;
		while((len = fis.read(arr)) != -1) {
			baos.write(arr,0,len);
		}
		fis.close();
		System.out.println(baos);
	}
}

对象操作流(ObjectOutputStrean序列化)

  • 构造: new ObjectOutputStream(FIleOutputStream(“文件名”));
  • 什么是对象操作流:该流可以将一个对象写出,或者读取对象到程序中,也就是执行了序列化和反序列化的操作;
  • 序列化和反序列化:比如你玩游戏有装备、等级、攻击力等数据时,你玩了几把后数据有变化,然后不玩了退出,这时就要保存数据库某个文件,就是通过序列化来操作的,序列就是输出流(写),而你下次玩,你的等级等信息就要被读出来,这时就使用反序列化来操作,反序列化就是输入流(读);
  • 如果一个对象想被序列化和反序列化就得指定规则,实现Serializable;
  • 通过序列化写出,文件中数据看肯定是乱码的,因为底层还是字节传输,看构造;但是不影响,比如玩游戏你会去看文件吗,只要保证下次玩的时候,等级等数据没变就行;
public class Demo {
	public static void main(String[] agrs) {
			Student s1 = new Student("张三",18);
			Student s2 = new Student("李四",19);
			ObjectOutputStream oos = new ObjectOutputStream(FileOutputStream("aa.txt"));
			oos.writeObject(s1);
			oos.writeObject(s2);
			oos.close();
	}
}
//比如创建了一个学生对象,有名称,姓名二种数据
特别注意学生对象必须实现Serializable接口;

对象操作流(ObjectInputStrean反序列化)

//将上面写出后的文件的数据打印到控制台
public class Demo {
	public static void main(String[] agrs) throws IOException,ClassNotFoundException{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("aa.txt"));
		Student s1 = (Student)ois.readObject();
		Student s2 = (Student)ois.readObject();
		System.out.println(s1);
		System.out.println(s2);
		ois.close();
	}
}

对象操作流优化

  • 当你不知道文件存了几个对象的时候,很可能在读取的时候出现多读了,就会出现异常;使用集合就可以解决这个问题,还解决了复用性;
//序列化 假设学生对象,并实现了Serializable
public class Demo_ObjectOutputStream {
	public static void main(String[] agrs) throws IOException{
		Student s1 = new Student("李超武", 19, 100);
		Student s2 = new Student("吴非凡", 19, 99);
		Student s3 = new Student("谢仔晟", 19, 22);
		ArrayList<Student> list = new ArrayList<>();
		list.add(s1);
		list.add(s2);
		list.add(s3);
		ObjectOutputStream oos = new ObjectOutputStream(new FIleOutputStream("aa.txt"));
		oos.writeObject(list);  //写了一个集合对象;
		oos.close();
	}
}
/反序列化
public class Demo_ObjectInputStream {
	public static void main(String[] agrs) throws IOException,ClassNotFoundException{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("aa.txt"));
		ArrayList<Student> list = (ArrayList<Student>)ois.readObject();  //将集合对象读出来
		for(Student student : list) {
			System.out.println();
		}
		ois.close();
	}
}

对象操作流ID号

  • 要写出的对象必须实现Serializable接口才能实现序列化
  • 当你更新了你的对象时,而你没有先写出,而是直接读,就会报错,其中控制台会出现以前id和现在id;所以更清楚的告诉你要你先写出;
  • 代码null
  • 在对象中 :private static final lone serialversionUID = 1L;
    异常代码 Exception in thread “main” java.io.InvalidClassException: com.lichaowu.bean.Student; local class incompatible: stream classdesc serialVersionUID = 2, local class serialVersionUID = 3

打印流

  • 什么是打印流:该流可以很方便的将对象的toString()结果输出,并且自动加上换行,而且可以使用自动刷出的模式
  • System.out返回的就是一个PrintStream,其默认向控制台输出信息
PrintStream ps = System.out;
ps.println(97);   //底层会将97转成字符串进行打印
ps.println(s1);  //s1是对象,底层会调用toString()
  • 打印流使用方法
  • 打印流只操作写出
PrintWriter pw = new PrintWriter(new FileOutputStream("a.txt"),true);
pw.println(97);   //刷新只争对prinln()

标准输入输出流

  • 什么是标准输入输出流
    System.in返回的是InputStream,标准输入流,默认可以从键盘输入数据读取字节数据
    System.out返回的是PrintStream,标准输出流,默认可以向控制台输出字符和字节数据

  • 修改标准输入输出流

public class Demo {
	public static void main(String[] agrs) {
		//修改标准输入流,从a.txt中读取,不再是控制台
		System.in(new FileInputStream("a.txt"));
		//修改标准输出流,输出到b.txt,不再是控制台
		System.out(new PrintStream("b.txt"));
		InputStream is = System.in;
		PrintStream ps = System.out;
		int b;
		while((b = is.read()) != -1) {
			ps.write(b);
		}
		is.close();
		ps.close();s
	}
}

修改标准输入输出流进行拷贝图片

public class Test {
	public static void main(String[] agr) throws IOException{
		System.setIn(new FileInputStream("qq.jpg"));
		System.setOut(new PrintStream("copy.jpg"));
		InputStream is = System.in;
		PrintStream ps = System.out;
		int b;
		while((b = is.read()) != -1) {
			ps.write(b);
		}
		is.close();
		ps.close();
	}
}

两种方式实现键盘录入

  • BufferedReader
public class Demo {
	public static void main(String[] agrs) throws IOException{
		BufferedReader br = new BufferedReader(InputStreamReader(System.in));
		String line = br.readLine();  //读取一行
		System.out.println(line);
	}
}
  • Scanner(使用这种,功能更加强大)
public class Demo {
	public static void main(String[] agrs) {
		Scanner sc = new Scanner(System.in);
		String line = sc.nextLine();
		System.out.println(line);
	}
}

随机访问流

  • 可以设置指定位置读写,具备读和写操作
  • RandomAccessFile类
  • 父类是Object,所以不是流,但具备流功能,在IO包下
  • 使用方法
public class Demo {
	public static void main(String[] agrs) {
		//	第二个参数代表读和写,请查看API文档
		RandomAccessFile raf = new RandomAccessFile("aa.txt", "rm");
		//raf.read(97);//写出
		//int b = raf.write();//读取
		//raf.seek(10); //在文件中设置第10个字节的位置读取第0个开始,用于多线程下载
	}
}

数据输入输出流

  • 我们在用字节流read()方法读写数据的时候,是一个字节一个字节读写的,而基本数据类型有四个字节、八个字节不等,这时我们想解决这个问题就用数据输入输出流
  • DataInputStream&&DataOutputStream
  • 例如按long大小写出一个数字,写出时该数据占8个字节,读取时也可以按照片long类型读取,一次读取8个字节
  • 使用方法
//写出
public class Demo {
	public static void main(String[] agrs) throws IOException{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("aa.txt"));
		dos.writeInt(998);
		dos.writeInt(999);
		dos.close();
	}
//读取
public class Demo {
	public static void main(String[] agrs) throws IOException{
		DataInputStream dis = new DataInputStream(new FileInputStream("aa.txt"));
		dis.readInt(998);
		dis.readint(999);
		dis.close();
	}
}

Properties的使用

  • 是Hashtable的子类

  • 主要应用于配置文件

public class Demo {
	public static void main(String[] agrs) {
		//不用指定泛型
		Properties prop = new Properties();
		prop.put("姓名", "张三");
		System.out.println(prop):
	}
}
  • 特殊方法
    1、public Object setProperties(String key, String value);设置键和值
    2、public String getProperties(String key);通过键获取值
    3、public Enumeration stringPropertyNames();获取该集合中所有键,返回一个枚举;
    4、Enumeration中hasMoreElements();遍历每一个键,返回boolean,配合while()使用
    5、Enumeration中nextElement();获取该键的名称,返回一个String
//遍历Properties
public class Demo {
	public static void main(String[] agrs) {
		Properties prop = new Properties();
		prop.setProperty("name", "张三");
		prop.setProperty("tal", "15074762880");
		Enumeration<String> en = (Enumeration<String>)prop.propertyNames();
		while(en.hasMoreElements()) {
			System.out.println(key + " = " + prop.getProperty(en.nextElement()));
		}
	}
}
  • load()&&store()功能
    public void load(InputStream inStream);//输入流
    public void store(OutputStream, String comments)//,输出流就是对文件的一种描述
public class Demo {
	public static void main(String[] agrs) {
		Properties prop = new Properties();
		//指定读取配置文件,读到该集合中
		prop.load(new FileInputStream("config.properties"));
		prop.setProperty("name", "张三");//读取后再修改
		//写到配置文件中,注释为:学生信息
		prop.store(new FileOutputStream("config.properties"),"学生信息");
	}
}

配置文件效果图:
在这里插入图片描述

管道流

  • 多线程的通信
  • connect():输入输出流的连接
class Send Runnable {
	private PipedOutputStream pos = null;
	public Send() {
		this.pos = new PipedOutputStream();	
	}
	public void run() {
		String str = "hello world!";
		try {
			this.pos.write(str.getBytes());
		}catch (IOException e) {
			e.printStackTrace();
		}
		pos.close();   //同上异常
	}
	public PipedOutputStream getPos() {
		return this.pos;
	}
}
class Receive Implements Runnable {
	private PipedInputStream pis = null;
	public Receive() {
		this.pis = new PipedInputStream();
	}
	public void run() {
		byte[] arr = new byte[1024 * 8];
		int len = 0;
		len = this.pis.read(arr);  //有异常同上
		System.out.println(new String(arr, 0, len));
		pis.close();    ///有异常同上
	}
}
public class Demo {
	Send s = new Send();
	Receive r = new Receive();
	s.getPos().connect(r.getPis());  //有异常同上
	new Thread(s).start();
	new Thread(r).start();
}

压缩流

  • 在操作系统中经常可以看到各种压缩文件:ZIP,JAR,GZ

  • 在JAVA中为了减少传输时的数据是量提拱了专门的压缩流,可以将文件或文件夹压缩成ZIP、JAR、GZIP等文件格式;实现如下:

  • ZipEntry类:在每一个压缩文件中都会存在多个子文件,那么这每一个子文件在JAVA中就使用ZipEntry表示;
    public ZipEntry(String name); 创建对象并指定要创建的ZipEntry名称
    public void isDirectory();判断是否是目录

  • ZipOutputStream类:此类功能就是完成ZIP格式输出的,虽然在util包中,但父类是OutpuStream类,就是一个输出流;
    public void putNextEntry(Enetry e);在压缩文件中,每一个压缩的内容都可以用一个ZipEntry表示,所以在进行压缩之前必须通过putNextEntry设置一个ZipEntry就可以了;
    public void setComment(String comment);设置注释

//压缩文件
public class Demo {
	public static void main(String[] agrs) throws IOException{
		File file = new File("aa.txt");  //要压缩的谇
		File zipFile = new File("aa.zip");  //压缩到哪个文件
		FileInputStream fis = new FileInputStream(file);
		ZipOutputStream zos = new ZipOutputStream(zipFile);
		zos.setComment("李超武文件");   //注释文件
		zos.putNextZipEntry(new ZipEntry(file.getName()));
		int b = 0;
		while((b = fis.read()) != -1) {
			zos.write(b):
		}
		fis.close();
		zos.close();
	}
}
//压缩文件夹(文件夹中没有文件夹只有文件)
public class Demo {
	public static void main(String[] agrs) throws IOException{
		File dir = new File("aaa");
		File zipFile = new File("zipFile.zip");
		FileInputStream fis = null;
		ZipOutputStream zos = new ZipOutputStream(zipFile);
		zos.setComment("李超武文件夹");
		if(dir.isDirectory()) {
			File[] list = dir.listFiles();
			for (File file2 : list) {
				fis = new FileInputStream(file2);
				zos.putNextEntry(new ZipEntry(file.getName() + File.separator + file2.getName()));
				int b = 0;
				while((b = fis.read()) != -1) {
					zos.write(b);
				}
				fis.close();
			}
		}
		zos.close();
	}
}
//压缩文件夹(文件夹中还有文件夹递归调用)
public class Dmo14_ZipOutputStream {
	public static void main(String[] agrs) throws IOException{
		File dir = new File("C:\\Users\\MAC\\Desktop\\新建文件夹 (2)");
		File zipFile = new File("C:\\Users\\MAC\\Desktop\\qqq1.zip");
		FileInputStream fis = null;
		ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
		zos.setComment("哈哈只只保健人人");
		get(dir,fis,zos);
		zos.close();
		
	}
	public static void get(File dir,FileInputStream fis,ZipOutputStream zos) throws IOException{
		File[] list = dir.listFiles();
		int b = 0;
		for (File file : list) {
			if(file.isFile()) {
				fis = new FileInputStream(file);
				zos.putNextEntry(new ZipEntry(dir.getName() + File.separator + file.getName()));
				while((b = fis.read()) != -1) {
					zos.write(b);
				}
				fis.close();
			} else {
				get(file,fis,zos);
			}
		}
	}
}
  • ZipFile类:是一个专门表示压缩文件的类
    public ZipFile(File file);根据File类实例化ZipFile对象
    public ZipEntry getEntry(String name);根据名称找到对应的ZipEntry
    public InputStream getInputStream(ZipEntry entry);根据ZipEntry获取InputStream实例
    public String getName();得到压缩文件的路径名称;
//解压文件
public class Demo {
	public static void main(String[] agrs) {
		File file = new File("aa.zip");
		File outFile = new File("aa.txt");
		ZipFile zipFile = new ZipFile(file);
		ZipEntry entry = new ZipEntry(outFile.getName());
		FileOutputStream fos = new FileOutputStream(outFile);
		InputStream fis = zipFile.getInputStream(entry);
		int b = 0;
		while((b = fis.read()) != -1) {
			fos.write(b);
		}
		fis.close();
		fos.close(); 
	}
}
这个操作有一个问题,必须知道压缩文件中每一个压缩实体文件的名称才可以进行解压。而如果是文件夹呢?
  • ZipInputStream类:获取每一个ZipEntry
//解压文件夹(文件夹内没有文件夹)
public class Demo {
	public static void main(String[] agrs) throws IOException{
		File file = new File("C:" + File.separator + "aa.zip");
		ZipFile zipFile = new ZipFile(file);
		ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
		File outFile = null;
		ZipEmtry entry = null;
		InputStream is = null;
		OutputStream os = null;
		int b = 0;
		while((entry = zis.getNextEntry) != null) {
			outFile = new File("C:" + File.separator + entry.getName());
			if(!outFile.getParentFile().exists()) {
				outFile.getParentFile().mkdir();
			}
			if(!outFile.exists()) {
				outFile.createNewFile();
			}
			is = zipFile.getInputStream(entry);
			os = new FIleOutputStream(outFile);
			while((b = is.read()) != -1) {
				os.write(b):
			}
			is.close():
			os.close(); 
		}
	}
}
  • 总结:1、压缩文件中的每一个压缩实体都使用ZipEntry保存,一个压缩文件中可能包含一个或多个的ZipEntry对象;
    2、在JAVA中可以进行ZIP、JAR、GZ三种格式的压缩支持,操作流流程基本一致;
    3、ZipOutputStream可以进行压缩输出,但是输出的位置不一定是文件;
    4、ZipFile表示一个压缩文件,可以通过ZipEntry得到InputStream流;
    5、ZipInputStream可以得到每一个实体,但确无法得到每一个实体的输入流;

回退流(PushbackInputStream)

  • 给了用户第二次读的机会;如果读进来的数据有某些地方不想要,可以把读取进来的数据重新退回到输入流的缓冲区;
//下面以一个简单的程序为例,进行回退流的讲解。现在,内存中有"www.lichaowu.com"的字符串数据。只要输入.则执行回退,就是不要点;
public class Demo {
	public static void main(String[] agrs) throws IOException{
		String str = "www.lichaowu.com";
		ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
		PushbackInputStream pis = new PushbackInputStream(bais);
		System.out.println("读取之后的数据为:");
		int b = 0;
		while((b = pis.read()) != -1) {
			if('.' == b) {
				pis.unread(b);
				b =  pis.read();
			}else {
				System.out.print((char)b);
			}
 		}
	}
}

经典题目

  • 统计文件夹大小(文件夹不能直接获取大小)
public class Test8 {
	public static void main(String[] agrs) {
		File dir = getFile();
		long size = getSize(dir);
		System.out.println(size);
	}
	public static long getSize(File dir) {
		long size = 0;
		File[] filearr = dir.listFiles();
		for (File file : filearr) {
			if(file.isFile()) {
				size += file.length();
			} else {
				size = size + getSize(file);
			}
		}
		return size;
	}
	//录入文件夹
	public static File getFile() {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入文件路径: ");
		while(true) {			
			String line = sc.nextLine();
			File file = new File(line);
			if(!file.exists()) {
				System.out.println("错误路径,重新输入!");
			}else if(file.isFile()){
				System.out.println("文件路径,重新输入!");
			}else {
				System.out.println("录入正确!");
				return file;
			}
		}
	}
}
  • 删除文件夹(文件夹不能直接删除,必须先删除文件夹里的文件)
/**
 * 删除文件夹
 * 文件夹如果里面有文件不能直接删除;
 * @author MAC
 *  */
public class Test9 {
	public static void main(String[] agrs) {
		File dir = getFile();
		fileDelete(dir);
	}
	//删除文件,不走回收站
	public static void fileDelete(File dir) {
		File[] subFiles = dir.listFiles();
		for (File file : subFiles) {
			if(file.isFile()) {
				file.delete();
			}else if(file.isDirectory()){
				fileDelete(file);
			}
		}
		dir.delete();
	}
	//录入正确路径
	public static File getFile() {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入要删除的文件夹路径: ");
		while(true) {
			String line = sc.nextLine();
			File dir = new File(line);
			if(!dir.exists()) {
				System.out.println("非法路径,重新录入!");
			}else if(dir.isFile()) {
				System.out.println("文件路径,重新录入!");
			}else {
				System.out.println("录入正确!");
				return dir;
			}
		}
	}
}
  • 拷贝文件夹
//文件夹的拷贝
public class Test10 {
	public static void main(String[] agrs) throws IOException{
		File src = getFile();
		File dest = getFile();
		if(src.equals(dest)) {
			System.out.println("两个文件夹相等,不能进行拷贝操作!");
		}else {			
			copy(dest, src);
		}
	}
	public static void copy(File dest, File src) throws IOException{
		File newDir = new File(dest, src.getName());
		newDir.mkdir();  //创建文件夹
		File[] subFile = src.listFiles();
		for (File file : subFile) {
			if(file.isFile()) {
				BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(newDir,file.getName())));
				int b = 0;
				while((b = bis.read()) != -1) {
					bos.write(b);
				}
				bis.close();
				bos.close();
			}else {
				copy(newDir, file);
			}
		}
		
	}
	public static File getFile() {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入你要拷贝的文件夹路径: ");
		while(true) {
			String line = sc.nextLine();
			File dir = new File(line);
			if(!dir.exists()) {
				System.out.println("非法路径,重新录入!");
			}else if(dir.isFile()) {
				System.out.println("文件路径,重新录入!");
			}else {
				System.out.println("录入成功!");
				return dir;
			}
		}
	}
}
  • 层级打印
/**
 * 格式化层级打印文件夹
 * @author MAC
 *  */
public class Test11 {
	public static void main(String[] agrs) {
		File dir = getDir();
		printlev(dir,0);
	}
	public static void printlev(File dir, int lev) {
		File[] subFile = dir.listFiles();
		for (File file : subFile) {
			for(int i = 0; i <= lev; i++) {
				System.out.print("\t");
			}
			System.out.println(file);
			if(file.isDirectory()) {
				printlev(file,lev + 1);
			}
		}
	} 
	public static File getDir() {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入文件夹路径:");
		while(true) {
			String line = sc.nextLine();
			File dir = new File(line);
			if(!dir.exists()) {
				System.out.println("非法路径!");
			}else if(dir.isFile()) {
				System.out.println("文件夹路径!");
			}else {
				System.out.println("录入正确!");
				return dir;
			}
		}
	}
}
  • 递归实现斐波那契数列
/**
 * 递归实现斐波那契数列 
 * @author MAC
 *  */
public class Test12{
	public static void main(String[] agrs) {
		//使用数组做
		//Demo1();
		//使用递归来做
		System.out.println(fun(12));
	}
	public static int fun(int num) {
		if(num == 1 || num == 2) {
			return 1;
		}
		return fun(num - 1) + fun(num - 2);
	}
	public static void Demo1() {
		int[] arr = new int[12];
		arr[0] = 1;
		arr[1] = 1;
		for(int i = 2; i < arr.length; i++) {
			arr[i] = arr[i - 2] + arr[i - 1];
		}
		for (int i : arr) {
			System.out.print(i + "\t");
		}
	}
}
  • 求1000阶乘的所有零和尾部零(非递归做)
public class Demo{
	public static void main(String[] agrs) {
		BigInteger bi1 = new Biginteger("1");
		for(int i = 1; i < 1000; i++) {
			BigInteger bi2 = new BigInteger(i + "");
			bi1 = bi1.multiply(bi2);  //乘法
		}
		System.out.println("1000阶乘为:" + bi1);
		String str = bi1.toString();
		int com1 = 0;
		for(int j = 0; j < str.length(); j++) {
			if(str.charAt(j) == '0') {
				com1++;
			}
		}
		System.out.println("所有零个数 : " + com1);
		StringBuufer sb = new StringBuffer(str);
		str = sb.reverse().toString(); //字符串反转
		int com2 = 0;
		for(int k = 0; k < str.length(); k++) {
			if(str.charAt(k) != '0') {
				breadk;
			}else {
				com2++;
			}
		}
		System.out.println("尾部零个数有: " + com2);
	}
}
  • 用递归求出阶乘1000的尾部零(没整明白)
public class Demo {
	public static void main(String[] agrs) {
		System.out.println(fun(1000));
	}
	public static int fun(int num) {
		if(num > 0 && num < 5) {
			return 0;
		} else {
			return num / 5 + fun(num / 5);
		}
	}
}
  • 约瑟夫环
/*
 * 约瑟 夫环
 */
public class Test15 {
	public static void main(String[] agrs) {
		System.out.println(getLucklyNum(8));
	}
	/*
	 * 获取幸运数字 
	 * 1、返回值类型int
	 * 2、参数列表 int num ;数字个数
	 */
	public static int getLucklyNum(int num) {
		ArrayList<Integer> list = new ArrayList<>();
		for(int i = 1; i <= num; i++) {
			list.add(i);
		}
		int count = 1;  //用来数数的,只要是三的倍数就杀人
		for(int i = 0; list.size() != 1; i++) {
			if(i == list.size()) {
				i = 0;
			}
			if(count % 3 == 0) {
				list.remove(i--);	
			}
			count++;
		}
		return list.get(0);
	}
}
  • 自己实现录入数据
/**
 * 录入数据
 * @author MAC
 *  */
public class Test16 {
	private BufferedReader br = null;
	public Test16() {
		this.br = new BufferedReader(new InputStreamReader(System.in));
	}
	public String getString(String info) {
		String temp = null;
		System.out.print(info);
		try {
			temp = br.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return temp;
	}

	public int getInt(String info,String err) {
		int temp = 0;
		while(true) {			
			String str = this.getString(info);
			if(str.matches("\\d+")) {
				temp = Integer.parseInt(str);
				break;
			} else {
				System.out.println(err);
			}
		}
		return temp;
	}
	public Date getDate(String info,String err) {
		Date date = null;
		while(true) {
			String str = this.getString(info);
			if(str.matches("\\d{4}-\\d{2}-\\d{2}")) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd");
				try {
					date = sdf.parse(str);
				} catch (ParseException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			}else {
				System.out.println(err);
			}
		}
		return date;
	}
	public float getFloat(String info,String err) {
		float temp = 0;
		while(true) {
			String str = this.getString(info);
			if(str.matches("\\d+.?\\d")) {
				temp = Float.parseFloat(str);
				break;
			}else {
				System.out.println(err);
			}
		}
		return temp;
	}
	public static void main(String[] agrs) throws IOException{
		int i = 0;
		int j = 0;
		Test16 t = new Test16();
		i = t.getInt("请输入第一个数字 :", "输入的是必须是数字请重新输入!");
		j = t.getInt("请输入第二个数字 :", "输入的是必须是数字请重新输入!");
		System.out.println(i + j);
		float f1 = 0;
		float f2 = 0;
		f1 = t.getFloat("请输入第一个小数:", "输入的是必须是小数请重新输入!");
		f2 = t.getFloat("请输入第二个小数:", "输入的是必须是小数请重新输入!");
		System.out.println(f1 + f2);
		Date d = t.getDate("请输入一个日期 : ", "输入的是必须是日期请重新输入!");
		System.out.println(d);
	}
}
  • 结合上面代码,设计一个小系统
//Operate类,操作类
public class Operate {
	private Operate(){}
	public static void add() {
		System.out.println("增加数据操作");
	}
	public static void delete() {
		System.out.println("删除数据操作");
	}
	public static void Updata() {
		System.out.println("修改数据操作");
	}
	public static void find() {
		System.out.println("显示数据操作");
	}
}
//Menu类 显示菜单类
public class Menu {
	public Menu() {
		this.show();
	}
	public void show() {
		System.out.println("==== Xxx系统 ====");
		System.out.println("    [1]、增加数据");
		System.out.println("    [2]、删除数据");
		System.out.println("    [3]、修改数据");
		System.out.println("    [4]、显示数据");
		System.out.println("    [0]、退出系统");
		Test16 t = new Test16();  //上面那个录入数据类
		int i = t.getInt("请选择:", "录入错误");
		switch (i) {
			case 1:
				Operate.add();
				break;
			case 2:
				Operate.delete();
				break;
			case 3:
				Operate.Updata();
				break;
			case 4:
				Operate.find();
				break;
			case 0:
				System.exit(0);
				break;
			default:
				System.out.println("请输入正确的操作数据!");
				break;
		}
	}
}
//Test测试类
public class Test {
	public static void main(String[] agrs) {
		Menu m = new Menu();
	}
}

开发总结:在开发中一定要先完成功能,之后再考虑类的设计。主方法就是一个客户端,代码越少越好;

一些面试题

  1. 字节流和字符流有什么区别?

字符流处理的单元为两个字节的Unicode字符,分别操作字符、字符数组、字符串;而字节流处理的单元为一个字节,操作字节和字节数组。所以字符流是由JVM将字节转化为2个字节的Unicode字符为单位的字符而成的,如果是视频、音频、图片等数据用字节最好,不然用字符流可能会数据丢失;字符流用于中文;

  1. 什么是序列化,如体实现序列化?

序列化就是一种处理对象流的机制;可以称对象操作流;所谓对象流也就是将对象的内容进行流化(将对象转换成二进制)。可以对流化后的对象进行读写操作。
1、对象实现Serializable接口,没有方法,只一种规则;
2、ObjectOutputStream和ObjectInputStream
3、序列化:对象->字节序列化->文件的过程
4、反序列化:文件->字节序列化->对象的过程

  1. 什么是比特(Bit)? 什么是字节(Byte)什么是字符(char)?各有什么区别?

Bit是最小传输单位,Byte是最小存储单位 1 Byte = 8 Bit, char是一种基本数据类型 1 char = 2 byte;

  1. BufferedReader属于哪种流?它主要是用来做什么的?它里面有什么经典的方法?

缓冲区字符流;输入速度快;提高效率;有readLine();读取一行的方法,newLine();换行的方法

  1. 如果我要打印不同类型的数据到数据源,那么适合用哪个流?

打印流PrintStream字节流、PrintWriter字符流

  1. 如果我要对字节流进行大量读取操作,要用哪个流;

哪个快哪个好啊。BufferedInputStream\BufferedOutputStream

  1. 怎么把输出字节流转换为输出字符流?

转成高效字符流
new BufferedWriter(new OutputStreamWriter(new FIleOutputStream(“文件”)));

  1. 说说你对IO流的了解?

IO流就是管道内,分为输入输出部分,分别对应读数据和写数据;

上一篇 多线程我所知道的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值