声明:学基础,在校学生,本文所有内容来自书本和视频,然后通过自己的理解和筛选编写而来,如有理解不到位的写得不到位的地方,欢迎评论指错!!!(仅做学习交流)
笔者: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();
}
}
开发总结:在开发中一定要先完成功能,之后再考虑类的设计。主方法就是一个客户端,代码越少越好;
一些面试题
- 字节流和字符流有什么区别?
字符流处理的单元为两个字节的Unicode字符,分别操作字符、字符数组、字符串;而字节流处理的单元为一个字节,操作字节和字节数组。所以字符流是由JVM将字节转化为2个字节的Unicode字符为单位的字符而成的,如果是视频、音频、图片等数据用字节最好,不然用字符流可能会数据丢失;字符流用于中文;
- 什么是序列化,如体实现序列化?
序列化就是一种处理对象流的机制;可以称对象操作流;所谓对象流也就是将对象的内容进行流化(将对象转换成二进制)。可以对流化后的对象进行读写操作。
1、对象实现Serializable接口,没有方法,只一种规则;
2、ObjectOutputStream和ObjectInputStream
3、序列化:对象->字节序列化->文件的过程
4、反序列化:文件->字节序列化->对象的过程
- 什么是比特(Bit)? 什么是字节(Byte)什么是字符(char)?各有什么区别?
Bit是最小传输单位,Byte是最小存储单位 1 Byte = 8 Bit, char是一种基本数据类型 1 char = 2 byte;
- BufferedReader属于哪种流?它主要是用来做什么的?它里面有什么经典的方法?
缓冲区字符流;输入速度快;提高效率;有readLine();读取一行的方法,newLine();换行的方法
- 如果我要打印不同类型的数据到数据源,那么适合用哪个流?
打印流PrintStream字节流、PrintWriter字符流
- 如果我要对字节流进行大量读取操作,要用哪个流;
哪个快哪个好啊。BufferedInputStream\BufferedOutputStream
- 怎么把输出字节流转换为输出字符流?
转成高效字符流
new BufferedWriter(new OutputStreamWriter(new FIleOutputStream(“文件”)));
- 说说你对IO流的了解?
IO流就是管道内,分为输入输出部分,分别对应读数据和写数据;