File类:
实例一:创建一个新文件
true
;如果指定的文件已经存在,则返回
false。
import java.io.File;
import java.io.IOException;
public class CreateFile {
public static void main(String[] args) {
File file = new File("E:/tmp/test.txt"); // 传入路径,实例化file对象
try {
file.createNewFile(); // 创建新文件
} catch (IOException e) {
e.printStackTrace();
}
}
}
将在E:\tmp中创建一个test.txt的文件(该文件大小为0byte)。注意:在传入路径的时候要么使用“/”,要么使用"\\"表示一个斜杠。
以上代码已经完成了文件的创建功能,但是如果在开发时按照以上的格式编写,则肯定会出现错误。因为在各个操作系统中,路径的分隔符是不一样的。例如:windows中使用“\”表示文件分隔符;而Linux中使用“/”表示文件分隔符。
如果java程序的可移植性继续保持,则最好是根据所在的操作系统来自动使用文件分隔符。使用File中的两个常量:
public static final String pathSeparator
public static final String separator
System.out.println("separator:"+File.separator);
System.out.println("pathSeparator:"+File.pathSeparator);
运行结果:
separator:\
pathSeparator:;
如果想让java程序继续保持可移植性,那么在编写路径的时候就应该使用File类中的常量。
修改以上程序:
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt"); // 传入路径,实例化file对象
try {
file.createNewFile(); // 创建新文件
} catch (IOException e) {
e.printStackTrace();
}
删除文件:
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
file.delete();
执行以上的程序,文件确实已经被删除了,但是在删除文件的时候应该先判断一下文件是否存在。
判断文件是否存在:
public boolean exists()
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
if (file.exists()) {
file.delete();//文件存在则删除之
} else {
System.out.println("文件不存在!");
}
综合创建、删除文件的操作:
import java.io.File;
import java.io.IOException;
public class CreateAndDeleteFile {
public static void main(String[] args) {
File file = new File("E:" + File.separator + "tmp" + File.separator
+ "test.txt");
if (file.exists()) {
if (file.delete()) {
System.out.println("文件删除成功!");
}
} else {
try {
if (file.createNewFile()) {
System.out.println("文件创建成功!");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
从程序的运行结果可以发现,所有的操作并不会立即执行,因为java是通过JVM与底层进行交互的,所以所有的操作都必须经过JVM,所以有可能产生延迟。
创建一个文件夹:
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.tt");
file.mkdir();
列出指定目录下的所有文件(包含目录):
public File[] listFiles()——以File对象数组的形式返回
File file = new File("E:"+File.separator);
String[] fileString = file.list();
for (String string : fileString) {
System.out.println(string);
}
操作二:使用File对象数组:
File file = new File("E:"+File.separator);
File[] files = file.listFiles();
for (File file2 : files) {
System.out.println(file2);
}
操作二打印的是文件的绝对路径。因此使用操作二较好。
判断指定路径是否目录:
File file = new File("E:"+File.separator);
if (file.isDirectory()) {
System.out.println(file.getPath()+"是目录!");
}else {
System.out.println(file.getAbsolutePath()+"不是目录!");
}
采用递归的形式列出指定目录下的所有文件(不含目录):
import java.io.File;
public class ListFile {
public static void main(String[] args) {
File file = new File("E:" + File.separator);
print(file);
}
public static void print(File file) { // 该方法被递归调用
if (file != null) { // 判断对象是否为空
if (file.isDirectory()) {
File[] files = file.listFiles(); // 列出全部的文件
if (files != null) { //因为有一些文件是操作系统不允许访问的
for (File file2 : files) {
print(file2); //递归调用
}
}
} else {
System.out.println(file);
}
}
}
}
RandomAccessFile类:
public RandomAccessFile(File file,String mode)throws FileNotFoundException
"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
"rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
"rwd" 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo01 {
public static void main(String[] args) throws IOException {
File file = new File("E:" + File.separator + "tmp" + File.separator
+ "test.txt");
RandomAccessFile rdf = new RandomAccessFile(file, "rw");// 读写模式,文件不存在则创建之
String name = null;
int age = 0;
name = "zhangsan"; // 字符串长度为8字节
age = 30; // 整数的长度为4字节
rdf.writeBytes(name);
rdf.writeInt(age);
name = "lisi ";
age = 31;
rdf.writeBytes(name);
rdf.writeInt(age);
name = "wangwu ";
age = 32;
rdf.writeBytes(name);
rdf.writeInt(age);
rdf.close();// 关闭
}
}
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo02 {
public static void main(String[] args) throws IOException {
File file = new File("E:" + File.separator + "tmp" + File.separator
+ "test.txt");
RandomAccessFile rdf = new RandomAccessFile(file, "r"); // 只读模式
String name = null;
int age = 0;
byte[] b = new byte[8]; // 开辟比特数组
// 读取第二个人的信息
rdf.skipBytes(12); // 跳过第一个人的信息
for (int i = 0; i < b.length; i++) {
b[i] = rdf.readByte(); // 读取一个字节
}
name = new String(b); // 将读取出来的比特数组变为字符串
age = rdf.readInt();
System.out.println("第二个人的信息-"+"姓名:" + name + "年龄:" + age);
//读取第一个人的信息
rdf.seek(0); //指针回到文件的开头
for (int i = 0; i < b.length; i++) {
b[i] = rdf.readByte();
}
name = new String(b);
age = rdf.readInt();
System.out.println("第一个人的信息-"+"姓名:" + name + "年龄:" + age);
//读取第三个人的信息
rdf.skipBytes(12); //此时文件指针位于第一个人的末尾
for (int i = 0; i < b.length; i++) {
b[i] = rdf.readByte(); // 读取一个字节
}
name = new String(b);
age = rdf.readInt();
System.out.println("第三个人的信息-"+"姓名:" + name + "年龄:" + age);
rdf.close(); // 关闭
}
}
以上的代码操作起来比较复杂,可以通过javaio中的流来操作使其简便。
字节流和字符流
字节流:
public class FileOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
//1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileOutputStream fos = new FileOutputStream(file);
//3.进行写操作(byte数组)
String info = "不悔梦归处,只恨太匆匆!";
byte[] b = info.getBytes(); //将String转化为byte数组
fos.write(b);
//4.关闭输出流
fos.close();
}
}
运行结果:
String info = "不悔梦归处,只恨太匆匆!";
byte[] b = info.getBytes(); //将String转化为byte数组
for (int i = 0; i < b.length; i++) {
fos.write(b[i]); //每次只写入一个字节
}
如果文件不存在则创建之,如果文件存在则覆盖之。如果想要进行追加的话,需要使用FileOutPutStream的另一个构造方法:public FileOutputStream(File file, boolean append)
如果想要字符串换行将字符串改变成如下:
String info = "\r\n不悔梦归处,只恨太匆匆!";
字节输入流(InputStream)
读取数据://1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileInputStream fis = new FileInputStream(file);
//3.进行读操作
byte[]b = new byte[1024];
fis.read(b);
//4.关闭输出流
fis.close();
System.out.println("内容是:"+new String(b));
修改以上程序为以下:
//1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileInputStream fis = new FileInputStream(file);
//3.进行读操作
byte[]b = new byte[1024];
int len = fis.read(b);
//4.关闭输出流
fis.close();
System.out.println("长度:"+len);
System.out.println("内容是:"+new String(b,0,len));
运行结果:
//1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileInputStream fis = new FileInputStream(file);
//3.进行读操作
byte[]b = new byte[(int) file.length()];//数组的大小由文件大小决定
int len = fis.read(b);
//4.关闭输出流
fis.close();
System.out.println("长度:"+len);
System.out.println("内容是:"+new String(b));
//1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileInputStream fis = new FileInputStream(file);
//3.进行读操作
byte[]b = new byte[(int) file.length()];//数组的大小由文件大小决定
for (int i = 0; i < b.length; i++) {
b[i] = (byte) fis.read();
}
//4.关闭输出流
fis.close();
System.out.println("内容是:"+new String(b));
以上的代码只适用于知道输入流大小的时候,如果我不知道大小呢?
//1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileInputStream fis = new FileInputStream(file);
//3.进行读操作
byte[]b = new byte[1024];
int len = 0;
int temp = 0; //接收每一个读取进来的数据
while ((temp = fis.read())!=-1) {
b[len++] = (byte) temp;
}
//4.关闭输出流
fis.close();
System.out.println("内容是:"+new String(b,0,len));
字符流:
字符流比字节流好在一点:就是可以直接输出字符串了,不用再将字符串转化为字节数组了。//1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileWriter fw = new FileWriter(file, true);//追加模式
String str = "\r\n不悔梦归处,只恨太匆匆!";
//3.写入内容
fw.write(str);
//4.关闭
fw.close();
字符输入流:
//1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileReader fr = new FileReader(file);
char[] c = new char[1024];
//3.读取内容
int len = fr.read(c);
System.out.println(new String(c,0,len));
//4.关闭
fr.close();
通过文件是否读到底的形式进行读取:
//1.使用File类找到一个文件
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
//2.通过父类实例化对象
FileReader fr = new FileReader(file);
char[] c = new char[1024];
//3.读取内容
int temp = 0; //接收每个内容
int len = 0;
while ((temp = fr.read())!=-1) {
c[len++] = (char) temp;
}
//4.关闭
System.out.println("内容是:"+new String(c,0,len));
fr.close();
字符流与字节流的区别:
通过一个代码来验证字符流使用了缓存:
File file = new File("E:\\tmp\\hello.txt");
FileOutputStream fos = new FileOutputStream(file);
String str = "我前年买了个登山包!";
byte[]b = str.getBytes();
fos.write(b); //写入数据
// fos.close();
以上的代码并没有关闭流,文件已经存在于磁盘上,并且已经有了内容。
File file = new File("E:\\tmp\\hello.txt");
FileWriter fr = new FileWriter(file);
String str = "我前年买了个登山包!";
fr.write(str); //写入数据
// fr.close();
执行以上代码由于没有关闭流,所以硬盘上虽然生成了文件,但是文件的内容是空的。也就字符流中的数据保存在了内存的缓冲区中,流关闭的时候刷新缓冲区后内容才显示出来。基于这个原理:如果没有关闭流,可以使用flush()方法强制刷新缓冲区。
硬盘上的文件以字节的方式进行保存并且也是以字节的形式进行网络的传输,而字符只是在内存中才会形成的,所以字节流的使用很广泛。
实例讲解:文件拷贝
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Copy {
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("输入参数不正确。");
System.out.println("例:java Copy 源文件路径 目标文件路径");
System.exit(1);
} else {
copyFile(args[0], args[1]);
}
}
private static void copyFile(String s, String d) {
File sFile = new File(s);
File dFile = new File(d);
if (!sFile.exists()) {
System.out.println("源文件不存在!");
System.exit(1);
} else {
try {
FileInputStream fis = new FileInputStream(sFile);
FileOutputStream fos = new FileOutputStream(dFile);
if (fis != null && fos != null) {
int temp = 0;
while ((temp = fis.read()) != -1) {
fos.write(temp); // 边读边写
}
System.out.println("复制完成!");
}
fis.close();
fos.close();
} catch (IOException e) {
System.out.println("复制失败!");
e.printStackTrace();
}
}
}
}
字节-字符装换流
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
Writer out = new OutputStreamWriter(new FileOutputStream(file)); //将字节流变为字符流
out.write("Hello World!"); //使用字符流输出
out.close();
}
}
以上是写入文件,读入文件的方式正好相反:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
File file = new File("E:"+File.separator+"tmp"+File.separator+"test.txt");
Reader reader = new InputStreamReader(new FileInputStream(file));
char[]c = new char[1024];
int len = reader.read(c);
reader.close();
System.out.println(new String(c, 0, len));
}
}
以上只是以文件为例,因为OutputStreamWriter中接收的类型是OutputStream,只要是字节输出流都可以使用字符的形式输出,而InputStreamReader中接收的类型是InputStream,只要是字节输入流都可以使用字符输出流操作。
内存操作流:
利用他们完成一个大小写装换的程序:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ByteArrayDemo {
public static void main(String[] args) {
String str = "HELLO"; // 定义一个字符串,全部由大写字母组成
ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());// 向内存中写入
ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 从内存中取出内容
int temp = 0;
while ((temp = bis.read()) != -1) {
char c = (char) temp; // 将读取的数字变为字符
bos.write(Character.toLowerCase(c)); // 将字符变为小写
}
// 所有的数据都在ByteArrayOutputStream中了
String newString = bos.toString(); // 取出内容
System.out.println(newString);
try {
bis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
管道流:
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
class Send implements Runnable {
private PipedOutputStream pos = null; // 管道输出流
public Send() {
this.pos = new PipedOutputStream(); // 实例化输出流
}
@Override
public void run() {
String str = "Hello World!";
try {
this.pos.write(str.getBytes());
catch (IOException e) {
e.printStackTrace();
try {
pos.close();
catch (IOException e) {
e.printStackTrace();
System.out.println("发送方发送信息:"+str);
}
public PipedOutputStream getPipedOutputStream() {
return this.pos;
}
}
class Receive implements Runnable {
PipedInputStream pis = null; // 管道输入流
public Receive() {
this.pis = new PipedInputStream(); // 实例化管道输入流
}
@Override
public void run() {
byte[] b = new byte[1024];
int len = 0;
try {
len = this.pis.read(b);// 读取内容
catch (IOException e) {
e.printStackTrace();
pis.close();
catch (IOException e) {
System.out.println("接收方接收信息:" + new String(b, 0, len));
}
public PipedInputStream getPipedInputStream() {
return this.pis;
}
}
public class PipeDemo {
public static void main(String[] args) {
Send s = new Send();
Receive r = new Receive();
try {
s.getPipedOutputStream().connect(r.getPipedInputStream()); // 连接管道
catch (IOException e) {
e.printStackTrace();
new Thread(s, "发送方").start();
new Thread(r, "接收方").start();
}
}
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">运行结果:</span>
接收方接收信息:Hello World!
打印流:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintStreamDemo01 {
public static void main(String[] args) {
try {
PrintStream ps = new PrintStream(new FileOutputStream(
"E:\\tmp\\test.txt"));
ps.print("Hello ");
ps.println("World!");
ps.print("1 + 1 = " + 2);
ps.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果:
格式化输出:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintStreamDemo02 {
public static void main(String[] args) {
try {
PrintStream ps = new PrintStream(new FileOutputStream(
"E:\\tmp\\test.txt"));
String name = "汤姆·杰克逊";
int age = 30;
float score = 96.3f;
char sex = 'M';
ps.printf("姓名:%s,年龄:%d,分数:%f,性别:%c", name,age,score,sex);
ps.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果:
如果觉得%d、%c不好记忆的话也可以直接使用%s,因为任何数据类型碰到String都向String靠拢。
ps.printf("姓名:%s,年龄:%s,分数:%s,性别:%s", name,age,score,sex);
运行结果:
System类对IO的支持
public static final InputStream in; //标准输入
public static final PrintStream out;//标准输出
public static final PrintStream err;//标准错误输出
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">观察以上的3个常量都使用了public static final关键字进行修饰,但是所有的单词的字母不是大写的,这属于Java的历史遗留问题。</span>
System.out
import java.io.IOException;
import java.io.OutputStream;
public class SystemDemo01 {
public static void main(String[] args) {
OutputStream os = System.out; //此时的输出流是向屏幕上输出
try {
os.write("hello world".getBytes()); //向屏幕输出
} catch (IOException e) {
e.printStackTrace();
}
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
谁为我实例化,我就具备了谁的能力!根据对象的多态性,如果实现的子类不同,那么完成的功能也不同。
System.err
public class SystemDemo02 {
public static void main(String[] args) {
String str = "Hello World!";
try {
System.out.println(Integer.parseInt(str));//抛出的是运行时异常
catch (NumberFormatException e) {
System.err.println(e);
}
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">运行结果,控制台输出:</span>
如果将上述代码的catch块中的System.err变成System.out则发现结果完全一样。以上的代码肯定可以使用System.out进行输出。
System.out和System.err的区别:
System.in:
import java.io.IOException;
import java.io.InputStream;
public class SystemDemo03 {
public static void main(String[] args) {
InputStream input = System.in; //从键盘读取数据
byte[]b = new byte[1024]; //开辟byte数组空间,读取数据
System.out.print("请输入内容:");
try {
int len = input.read(b);//接收数据
System.out.println("你的输入:"+new String(b,0,len));
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
你的输入:niasn3543#$%^
你的输入:123
你的输入:简?
判断标志位的方式:
import java.io.IOException;
import java.io.InputStream;
public class SystemDemo04 {
public static void main(String[] args) {
InputStream input = System.in; //从键盘读取数据
System.out.println("输入内容:");
StringBuffer sb = new StringBuffer();
int temp = 0; //接收数据
try {
while ((temp = input.read())!= -1) {
char c = (char) temp;
if ('\n' == c) { //输入回车跳出循环
break;
}
sb.append(c);
}
System.out.println("你的输入:\n"+sb);
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
import java.io.IOException;
import java.io.InputStream;
public class SystemDemo04 {
public static void main(String[] args) {
InputStream input = System.in; //从键盘读取数据
System.out.println("输入内容:");
StringBuffer sb = new StringBuffer();
int temp = 0; //接收数据
try {
while ((temp = input.read())!= -1) {
char c = (char) temp;
if ('\n' == c) { //输入回车跳出循环
break;
}
sb.append(c);
}
System.out.println("你的输入:\n"+sb);
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这时输入的长度没有限制了,但是输入中文一样会乱码(每个汉字是拆分成两次读入的)。
最好的解决方案是将全部的输入数据放到一块内存之中,之后一次性从内存中读取数据,这样所有的数据都只读了一次,不会有乱码,也不会有长度的限制。
输入、输出重定向
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class SystemDemo05 {
public static void main(String[] args) throws FileNotFoundException {
System.setOut(new PrintStream(new FileOutputStream("E:\\tmp\\red.txt")) ); //System.out输出重定向
System.out.println("你好"); //控制台看不到了,在文件中
System.out.println(1223);
}
}
输出重定向,所有的内容向文件中打印。
利用以上思想可以完成错误的重定向,System.out是用户希望看到的信息,一旦有错误最好写入文件。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class SystemDemo06 {
public static void main(String[] args) throws FileNotFoundException {
String str = "Hello World!";
try {
System.out.println(Integer.parseInt(str));
} catch (NumberFormatException e) {
System.setOut(new PrintStream(new FileOutputStream(
"E:\\tmp\\err.log")));
System.out.println(e);
} catch (Exception e) {
}
}
}
错误信息不会在控制台打印,而是重定向到了错误日志文件中。
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class SystemDemo07 {
public static void main(String[] args) throws FileNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
System.setErr(new PrintStream(bos)); //输出重定向
System.err.print("错误的的"); //向内存中输出
System.err.println("Hello!");
}
}
System.err的信息写入了内存。
为System.in重定向
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class SystemDemo08 {
public static void main(String[] args) throws IOException {
System.setIn(new FileInputStream("E:\\tmp\\demo.txt")); //输入重定向
InputStream input = System.in; //从文件中接收数据
byte[]b = new byte[1024];
int len = input.read(b); //接收
System.out.println("输入的内容是:"+new String(b, 0, len));
input.close();
}
}
运行结果:
BufferedReader类:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class BufferedReaderDemo {
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 将字节流变为字符流
String str = null; // 接受内容
System.out.println("请输入内容:");
try {
str = br.readLine();// 读取一行
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("输入的内容:\n" + str);
}
}
运行结果:
ndisnfisdn中国人5456dfds
输入的内容:
ndisnfisdn中国人5456dfds
IO操作实例:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Exec {
public static void main(String[] args) throws IOException {
int i = 0, j = 0;
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(System.in));
String str = null; // 接收数据
System.out.print("请输入第一个数据:");
str = bufferedReader.readLine();
i = Integer.parseInt(str);
System.out.print("请输入第二个数据:");
j = Integer.parseInt(bufferedReader.readLine());
System.out.println(i + " + " + j + " = " + (i + j));
}
}
以上确实完成了基本功能,但是有以下问题:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputData {
private BufferedReader buf = null;
public InputData() {
super();
this.buf = new BufferedReader(new InputStreamReader(System.in));
}
public String getString(String info) {
String temp = null;
System.out.println(info); // 打印提示信息
try {
temp = buf.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return temp;
}
public int getInt(String info, String err) {
int temp = 0;
String str = null;
boolean flag = true;
while (flag) {
str = this.getString(info);
if (str.matches("^\\d+$")) { // 判断是否由数字组成
temp = Integer.parseInt(str);
flag = false; // 结束循环
} else {
System.out.println(err); // 打印错误信息
}
}
return temp;
}
}
import java.io.IOException;
public class Exec {
public static void main(String[] args) throws IOException {
int i = 0, j = 0;
InputData inputData = new InputData();
i = inputData.getInt("请输入第一个数字", "输入的不是数字,请重新输入!");
j = inputData.getInt("请输入第二个数字", "输入的不是数字,请重新输入!");
System.out.println(i + " + " + j + " = " + (i + j));
}
}
对InputData进行进一步扩充(整数、小数、字符串、日期),得到以下的代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class InputData {
private BufferedReader buf = null;
public InputData() {
super();
this.buf = new BufferedReader(new InputStreamReader(System.in));
}
public String getString(String info) {
String temp = null;
System.out.println(info); // 打印提示信息
try {
temp = buf.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return temp;
}
public int getInt(String info, String err) {
int temp = 0;
String str = null;
boolean flag = true;
while (flag) {
str = this.getString(info);
if (str.matches("^\\d+$")) { // 判断是否由数字组成
temp = Integer.parseInt(str);
flag = false; // 结束循环
} else {
System.out.println(err); // 打印错误信息
}
}
return temp;
}
public float getFloat(String info, String err) {
float temp = 0;
String str = null;
boolean flag = true;
while (flag) {
str = this.getString(info);
if (str.matches("^\\d+.?\\d+$")) { // 判断小数
temp = Float.parseFloat(str);
flag = false; // 结束循环
} else {
System.out.println(err); // 打印错误信息
}
}
return temp;
}
public Date getDate(String info, String err) throws ParseException{
Date temp = null;
String str = null;
boolean flag = true;
while (flag) {
str = getString(info);
if (str.matches("^\\d{4}-\\d{2}-\\d{2}$")) { //^和$分别表示正则表达式的开头和结尾
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
temp = sdf.parse(str);
flag = false;
}else {
System.out.println(getString(err));
}
}
return temp;
}
}
public class Operation {
public static void add(){
System.out.println("你选择了【增加】");
}
public static void delete(){
System.out.println("你选择了【删除】");
}
public static void update(){
System.out.println("你选择了【更新】");
}
public static void find(){
System.out.println("你选择了【查找】");
}
public static void exit(){
System.out.println("你选择了【退出】\n系统退出。。。");
System.exit(0);
}
}
菜单显示类:
public class Menu {
public Menu() {
while (true) {
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].退出系统");
InputData inputData = new InputData();
int i = inputData.getInt("请选择:", "请输入正确的选项!");
switch (i) {
case 1:
Operation.add();
break;
case 2:
Operation.delete();
break;
case 3:
Operation.update();
break;
case 4:
Operation.find();
break;
case 0:
Operation.exit();
break;
default:
System.out.println("请选择正确的操作!");
break;
}
}
}
测试类:
public class ExecTest {
public static void main(String[] args) {
new Menu();
}
}
Scanner类:
使用Scanner接收键盘的输入:
import java.util.Scanner;
public class ScannerDemo01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // Scanner接收一个InputStream
System.out.println("输入数据:");
String str = scanner.next(); // 接收数据
System.out.println("输入的数据是:" + str);
}
}
比使用BufferedReader更加容易,但是以上的程序存在问题:
它只能读取空格之前的内容,如果想要输入空格就必须修改分隔符,将分隔符变成“\n”【回车表示】
public Scanner useDelimiter(String pattern)
修改分隔符:
import java.util.Scanner; public class ScannerDemo02 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // Scanner接收一个InputStream scanner.useDelimiter("\n"); //设置分隔符为回车 System.out.println("输入数据:"); String str = scanner.next(); // 接收数据 System.out.println("输入的数据是:" + str); } }
<span style="white-space:pre"> </span>运行以上程序没有任何问题,使用Scanner在进行操作的时候最好指定分隔符。
使用Scanner类可以进行方便地进行数字的输入:
XXX nextXXX()方法,该方法需要与boolean hasNextXXX()方法进行配合使用,例如:import java.util.Scanner; public class ScannerDemo03 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // Scanner接收一个InputStream System.out.println("输入数据:"); if (scanner.hasNextInt()) { int i = scanner.nextInt(); System.out.println("整数:"+i); } else { System.out.println("不是整数!"); } } }
接收:public String next(Pattern pattern)
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class ScannerDemo04 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // Scanner接收一个InputStream
String str = null;
Date date = null;
System.out.println("输入日期(yyyy-MM-dd):");
if (scanner.hasNext("^\\d{4}-\\d{2}-\\d{2}$")) { // 判断
str = scanner.next("^\\d{4}-\\d{2}-\\d{2}$"); // 接收
try {
date = new SimpleDateFormat("yyyy-MM-dd").parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
} else {
System.out.println("输入的日期格式错误!");
}
System.out.println(date);
}
}
Scanner还可以直接从文件中读取数据:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class ScannerDemo05 {
public static void main(String[] args) {
StringBuffer str = new StringBuffer();
try {
Scanner scanner = new Scanner(new File("E:/tmp/tmp.txt"));
while (scanner.hasNext()) {
str.append(scanner.next()).append("\n");
}
System.out.println("文件中的内容是:" + str);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
在使用Scanner类来读取文件的时候要考虑到换行的功能。
数据操作流(DataInputStream和DataOutputStream)
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataOutputStreamDemo {
public static void main(String[] args) throws IOException {
// 声明并实例化DataOutputStream对象
DataOutputStream dos = new DataOutputStream(new FileOutputStream(
"E:/tmp/data.txt"));
String[] names = { "衬衣", "手套", "围巾" }; // 商品名称数组
float[] price = { 98.3f, 30.3f, 50.5f }; // 商品价格数组
int[] nums = { 3, 2, 1 }; // 数量
for (int i = 0; i < names.length; i++) {
dos.writeChars(names[i]); // 写入名称
dos.writeChar('\t'); // 写入分隔符
dos.writeFloat(price[i]); // 写入价格
dos.writeChar('\t');
dos.writeInt(nums[i]);// 写入数量
dos.writeChar('\n');
}
dos.close();// 关闭输出流
}
}
执行以上程序将会生成文件E:\tmp\data.txt,但是用记事本打开会出现乱码,因为使用DataOutputStream写入的数据需要使用DataInputStream才能够进行读取!
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class DataInputStreamDemo {
public static void main(String[] args) throws IOException{
DataInputStream dis = new DataInputStream(new FileInputStream(
"E:/tmp/data.txt"));
String name = null; // 接收名称
float price = 0.0f; // 接收价格
int nums = 0; // 接收数量
char[] temp = null; // 接收商品名称的数组
int len = 0; // 保存读取数据的个数
char c = 0; // \u0000
while (true) {
temp = new char[200]; // 开辟空间
len = 0;
while ((c = dis.readChar()) != '\t') {
temp[len] = c;
len++;
}
name = new String(temp, 0, len);
price = dis.readFloat();
dis.readChar(); // 读取\t
nums = dis.readInt();
dis.readChar(); // 读取\n
System.out.printf("名称:%s 价格:%.2f 数量:%d\n", name, price, nums);
}
}
}
这个和随机访问很相似,DataInput接口和DataOutput接口,这两个接口彼此对应。
合并流(SequenceInputStream)
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.SequenceInputStream;
public class SequenceInputStreamDemo {
public static void main(String[] args) {
try {
InputStream is1 = new FileInputStream("E:/tmp/a.txt");// 输入流1
InputStream is2 = new FileInputStream("E:/tmp/b.txt"); // 输入流2
OutputStream os = new FileOutputStream("E:/tmp/ab.txt");// 输出流
SequenceInputStream sis = new SequenceInputStream(is1, is2);// 实例化合并流
int temp = 0; // 接收内容
while ((temp = sis.read()) != -1) {
os.write(temp);
}
sis.close();
is1.close();
is2.close();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
压缩流(ZipOutputStream、ZipFile、ZipInputStream)
压缩流的实现:
ZipOutputStream:
java.lang.Object
java.io.OutputStream
java.io.FilterOutputStream
java.util.zip.DeflaterOutputStream
java.util.zip.ZipOutputStream
从继承关系可以看出它是一个字节输出流
public void putNextEntry(ZipEntry e)
throws IOException
在压缩文件中,每一个压缩的实体都用一个ZipEntry表示,所以在进行压缩之前必须通过putNextEntry设置一个zipEntry即可。
public void setComment(String comment)
以上方法用来设置注释
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
File file = new File("E:/tmp/info.txt"); // 需要压缩的文件
File zipFile = new File("E:/tmp/info.zip"); // 压缩文件
InputStream is = new FileInputStream(file);
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
zos.putNextEntry(new ZipEntry(file.getName())); // 设置zipEntry对象
zos.setComment("Windows SystemFile");
int temp = 0;
while ((temp = is.read()) != -1) {
zos.write(temp); // 压缩输出
}
is.close();
zos.close();
}
}
运行结果:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipOutputStreamDemo02 {
public static void main(String[] args) throws IOException {
File file = new File("E:/tmp/test"); // 需要压缩的目录
File zipFile = new File("E:/tmp/testdir.zip"); // 压缩文件
InputStream is = null;
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
if (file.isDirectory()) {
File[] listFiles = file.listFiles(); // 列出全部文件
for (int i = 0; i < listFiles.length; i++) {
is = new FileInputStream(listFiles[i]);
zos.putNextEntry(new ZipEntry(file.getName() + File.separator
+ listFiles[i].getName())); // 设置zipEntry对象
zos.setComment("E:/tmp/test Files");
int temp = 0;
while ((temp = is.read()) != -1) {
zos.write(temp); // 压缩输出
}
}
}
is.close();
zos.close();
}
}
运行结果:
ZipFile类:
··import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class ZipFileDemo01 {
public static void main(String[] args) throws ZipException, IOException {
File file = new File("E:/tmp/info.zip"); // 压缩文件
File outFile = new File("E:/tmp/info_unzip.txt");
ZipFile zipFile = new ZipFile(file); // 实例化ZipFile对象
ZipEntry entry = zipFile.getEntry("info.txt");// 得到压缩实体
OutputStream os = new FileOutputStream(outFile);
InputStream is = zipFile.getInputStream(entry);
int temp = 0;
while ((temp = is.read()) != -1) {
os.write(temp);
}
is.close();
os.close();
}
}
以上程序对一个压缩文件进行了解压缩。以上程序中有一个问题:必须知道每一个压缩实体的名称才可以进行解压缩操作,如果是一个文件夹呢?
ZipInputStream:
java.lang.Object
java.io.InputStream
java.io.FilterInputStream
java.util.zip.InflaterInputStream
java.util.zip.ZipInputStream
它是InputStream的子类。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
public class ZipInputStreamDemo01 {
public static void main(String[] args) throws IOException {
File file = new File("E:/tmp/testdir.zip");
File outFile = null; // 输出文件的时候需要有文件夹的操作
ZipFile zipFile = new ZipFile(file); // 实例化zipFile对象
ZipEntry zipEntry = null; // 每一个压缩实体
ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
OutputStream os = null;// 定义输出流,用于输出每一个实体
InputStream is = null; // 定义输入流,读取每一个ZipEntry
while ((zipEntry = zis.getNextEntry()) != null) {
System.out.println("解压缩:" + zipEntry.getName() + "文件!");
outFile = new File("E:/tmp/" + zipEntry.getName());
if (!outFile.getParentFile().exists()) { // 如果输出文件夹不存在
outFile.getParentFile().mkdir();
}
is = zipFile.getInputStream(zipEntry); // 得到实体的输入流
os = new FileOutputStream(outFile); // 实例化文件输出流
int temp = 0;
while ((temp = is.read()) != -1) {
os.write(temp);
}
is.close();
os.close();
}
}
}
压缩文件中每一个压缩实体使用一个ZipEntry,一个zip文件中可能有多个ZipEntry。
回退流(PushbackInputStream):
操作回退流:
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
public class PushbackInputStreamDemo {
public static void main(String[] args) throws IOException {
String str = "www.imooc.com";
ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
PushbackInputStream pushbackInputStream = new PushbackInputStream(bais);
System.out.println("读取之后的数据为:");
int temp = 0;
while ((temp = pushbackInputStream.read()) != -1) {
if (temp == '.') {
pushbackInputStream.unread(temp); // 放回到缓冲区
temp = pushbackInputStream.read(); // 再读一遍
// System.out.print("退回" + (char) temp);
} else {
System.out.print((char) temp);
}
}
}
}
通过回退流可以给用户第二次读取的机会,仅仅只有这一个优点而已。
字符编码:
System.getProperty("file.encoding")
系统默认的编码时GBK,如果在程序中使用了iso8859-1编码,则肯定会出现乱码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class CharsetDemo02 {
public static void main(String[] args) throws IOException {
File file = new File("E:/tmp/info.txt");
OutputStream os = new FileOutputStream(file);
byte[] bytes = "你好,中国".getBytes("iso8859-1"); // 将字符编码强制改为iso8859-1
os.write(bytes); // 保存
os.close();
}
}
运行结果:
对象的序列化及其反序列化:
什么叫做对象的序列化?
一个对象产生之后实际上就在内存中开辟了一个存储空间,方便存储信息。
对象的序列化就是将一个对象变成二进制的数据流的一种方法,通过对象的序列化可以方便的实现对象的存储和传输。如果一个类的对象需要被序列化,则该类必须实现Serializable接口,该接口的定义如下:
1 public interface Serializable { 2 3 }
Serializable接口中没有任何方法,只表示该类有这样具备这样一种能力,属于标识接口。下面的一个Student因为实现了Serializable接口,所以它就是可序列化的了:
1 package io.Serializable; 2 3 import java.io.Serializable; 4 5 public class Student implements Serializable { 6 private String name; 7 private int age; 8 9 public Student(String name, int age) { 10 super(); 11 this.name = name; 12 this.age = age; 13 } 14 15 public String getName() { 16 return name; 17 } 18 19 public void setName(String name) { 20 this.name = name; 21 } 22 23 public int getAge() { 24 return age; 25 } 26 27 public void setAge(int age) { 28 this.age = age; 29 } 30 31 @Override 32 public String toString() { 33 return "Student [name=" + name + ", age=" + age + "]"; 34 } 35 36 }
以上的代码仅仅是实现了Serializable接口,其他部分并没有任何改变,以上的类产生的对象就是可序列化(二进制比特流)的了。
如果要进行对象的序列化必须依靠两个类:
ObjectInputStream和ObjectOutputStream
serialVersionUID
在对对象进行序列化和反序列化的时候要考虑到JDK版本的问题,如果序列化的JDK版本和反序列化的JDK版本不统一就会抛出异常。所以在对象序列化的操作中引入了一个serialVersionUID的常量。可以通过此常量验证版本的一致性。在进行反序列化的操作时,JVM会把传来的字节流中的serialVersionUID与本地响应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化的操作,否则就会抛出序列化版本不一致的异常。
如果使用Eclipse进行编写,如果没有指定serialVersionUID则会出现一些警告信息,如图:
按照Eclipse的提示,我们加上这个常量,这样这个类的设计就完成了。
对象的序列化和反序列化:
1 package io.Serializable; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.io.ObjectInputStream; 9 import java.io.ObjectOutputStream; 10 11 public class SerializableDemo { 12 13 public static void main(String[] args) { 14 15 File file = new File("E:" + File.separator + "tmp" + File.separator 16 + "stu.obj"); // 保存路径 17 try { 18 ObjectOutputStream oos = new ObjectOutputStream( 19 new FileOutputStream(file)); 20 21 Student[] students = { new Student("张三", 12), 22 new Student("李四", 15), new Student("王五", 18) }; 23 oos.writeObject(students); // 直接写入一个对象数组,因为数组也是对象 24 oos.close(); 25 26 ObjectInputStream ois = new ObjectInputStream(new FileInputStream( 27 file)); 28 Student[] stus = (Student[]) ois.readObject(); 29 ois.close(); 30 31 for (Student student : stus) { 32 System.out.println(student); 33 } 34 35 } catch (FileNotFoundException e) { 36 e.printStackTrace(); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } catch (ClassNotFoundException e) { 40 e.printStackTrace(); 41 } 42 43 } 44 45 }
运行结果:
Externalizable接口
被Serializable接口声明的类的对象的内容都能够被序列化,如果现在用户希望可以自己制定序列化的内容,则可以让一个类实现Externalizable接口,该接口的定义如下:
1 public interface Externalizable extends Serializable { 2 public void readExternal(ObjectInput in)throws IOException,ClassNotFoundException; 3 public void writeExternal(ObjectOutput out)throws IOException; 4 }
利用此接口修改之前的程序:
1 package io.Serializable; 2 3 import java.io.Externalizable; 4 import java.io.IOException; 5 import java.io.ObjectInput; 6 import java.io.ObjectOutput; 7 8 public class Student implements Externalizable { 9 private String name; 10 private int age; 11 12 public Student(String name, int age) { 13 super(); 14 this.name = name; 15 this.age = age; 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public int getAge() { 27 return age; 28 } 29 30 public void setAge(int age) { 31 this.age = age; 32 } 33 34 @Override 35 public String toString() { 36 return "Student [name=" + name + ", age=" + age + "]"; 37 } 38 39 @Override 40 public void readExternal(ObjectInput in) throws IOException, 41 ClassNotFoundException { 42 this.name = (String) in.readObject(); //读取属性 43 this.age = in.readInt(); 44 } 45 46 @Override 47 public void writeExternal(ObjectOutput out) throws IOException { 48 out.writeObject(this.name); //保存属性 49 out.writeInt(this.age); 50 } 51 52 }
1 package io.Serializable; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.io.ObjectInputStream; 9 import java.io.ObjectOutputStream; 10 11 public class SerializableDemo { 12 13 public static void main(String[] args) { 14 15 File file = new File("E:" + File.separator + "tmp" + File.separator 16 + "stu.obj"); // 保存路径 17 try { 18 ObjectOutputStream oos = new ObjectOutputStream( 19 new FileOutputStream(file)); 20 21 Student[] students = { new Student("张三", 12), 22 new Student("李四", 15), new Student("王五", 18) }; 23 oos.writeObject(students); // 直接写入一个对象数组,因为数组也是对象 24 oos.close(); 25 26 27 ObjectInputStream ois = new ObjectInputStream(new FileInputStream( 28 file)); 29 Student[] stus = (Student[]) ois.readObject(); 30 ois.close(); 31 32 for (Student student : stus) { 33 System.out.println(student); 34 } 35 36 } catch (FileNotFoundException e) { 37 e.printStackTrace(); 38 } catch (IOException e) { 39 e.printStackTrace(); 40 } catch (ClassNotFoundException e) { 41 e.printStackTrace(); 42 } 43 44 } 45 46 }
运行结果:
在使用Externalizable接口的时候需要原有的类中有无参构造,在Student类中加入无参构造后一切正常了!此外在Externalizable接口中也可以自定义哪些属性需要序列化,见以下代码:
1 @Override 2 public void readExternal(ObjectInput in) throws IOException, 3 ClassNotFoundException { 4 this.name = (String) in.readObject(); //读取属性 5 // this.age = in.readInt(); 6 } 7 8 @Override 9 public void writeExternal(ObjectOutput out) throws IOException { 10 out.writeObject(this.name); //保存属性 11 // out.writeInt(this.age); 12 }
以上代码在运行的时候age属性将不会序列化!
transient关键字:
在序列化对象的时候如果不需要某个属性被序列化可以使用transient关键字进行修饰。如此一来Externalizable接口就变得毫无用途。
1 private transient int age; //age属性不会被序列化
运行结果:
由此可见Externalizable接口的功能完全可以由Serializable接口和transient关键字的组合来取代!
JavaIO实例讲解:
package io.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/*此类专门用于保存和读取*/
public class FileOperate {
private File file = null;
public FileOperate(String pathName) {
this.file = new File(pathName);
}
/* 保存对象 */
public boolean save(Object object) throws Exception {
ObjectOutputStream oos = null;
boolean flag = false;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(object);// 对象写入
flag = true;
} catch (Exception e) {
throw e; // 将异常交给调用处处理
} finally {
if (oos != null) {
oos.close();
}
}
return flag;
}
/* 读取对象 */
public Object load() throws Exception {
Object object = null;
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(file));
object = ois.readObject();
} catch (Exception e) {
throw e;
} finally {
if (ois != null) {
ois.close();
}
}
return object;
}
}
学生类Student:
package io.demo;
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
实际操作类Operation:
package io.demo;
public class Operation {
public static void add() {
System.out.println("你选择了【增加】");
InputData inputData = new InputData();
FileOperate fileOperate = new FileOperate("E:/tmp/test.info");
String name = inputData.getString("请输入姓名:");
int age = inputData.getInt("请输入年龄:", "年龄必须是数字");
Student student = new Student(name, age);
try {
fileOperate.save(student); // 保存对象
System.out.println("信息添加成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void delete() {
System.out.println("你选择了【删除】");
InputData inputData = new InputData();
FileOperate fileOperate = new FileOperate("E:/tmp/test.info");
Student student = null;
try {
fileOperate.save(student); // 保存空对象
System.out.println("信息删除成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void update() {
System.out.println("你选择了【更新】");
FileOperate fileOperate = new FileOperate("E:/tmp/test.info");
try {
Student student = (Student) fileOperate.load();
InputData inputData = new InputData();
String name = inputData.getString("请输入姓名(原来的姓名:"
+ student.getName() + "):");
int age = inputData.getInt(
"请输入年龄(原来的年龄:" + student.getAge() + "):", "年龄必须是数字");
student = new Student(name, age);
fileOperate.save(student);
System.out.println("信息更新成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void find() {
System.out.println("你选择了【查找】");
FileOperate fileOperate = new FileOperate("E:/tmp/test.info");
try {
Student student = (Student) fileOperate.load();
System.out.println(student);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void exit() {
System.out.println("你选择了【退出】\n系统退出。。。");
System.exit(0);
}
}
菜单显示类Menu:
package io.demo;
public class Menu {
public Menu() {
while (true) {
this.show();
}
}
public void show() {
System.out.println("======= XXX系统 ========");
System.out.println("\t[1].增加数据");
System.out.println("\t[2].删除数据");
System.out.println("\t[3].更新数据");
System.out.println("\t[4].查找数据");
System.out.println("\t[0].退出系统");
InputData inputData = new InputData();
int i = inputData.getInt("请选择:", "请输入正确的选项!");
switch (i) {
case 1:
Operation.add();
break;
case 2:
Operation.delete();
break;
case 3:
Operation.update();
break;
case 4:
Operation.find();
break;
case 0:
Operation.exit();
break;
default:
System.out.println("请选择正确的操作!");
break;
}
}
}
处理输入类InputData
package io.demo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class InputData {
private BufferedReader buf = null;
public InputData() {
super();
this.buf = new BufferedReader(new InputStreamReader(System.in));
}
public String getString(String info) {
String temp = null;
System.out.println(info); // 打印提示信息
try {
temp = buf.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return temp;
}
public int getInt(String info, String err) {
int temp = 0;
String str = null;
boolean flag = true;
while (flag) {
str = this.getString(info);
if (str.matches("^\\d+$")) { // 判断是否由数字组成
temp = Integer.parseInt(str);
flag = false; // 结束循环
} else {
System.out.println(err); // 打印错误信息
}
}
return temp;
}
public float getFloat(String info, String err) {
float temp = 0;
String str = null;
boolean flag = true;
while (flag) {
str = this.getString(info);
if (str.matches("^\\d+.?\\d+$")) { // 判断小数
temp = Float.parseFloat(str);
flag = false; // 结束循环
} else {
System.out.println(err); // 打印错误信息
}
}
return temp;
}
public Date getDate(String info, String err) throws ParseException{
Date temp = null;
String str = null;
boolean flag = true;
while (flag) {
str = getString(info);
if (str.matches("^\\d{4}-\\d{2}-\\d{2}$")) { //^和$分别表示正则表达式的开头和结尾
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
temp = sdf.parse(str);
flag = false;
}else {
System.out.println(getString(err));
}
}
return temp;
}
}
测试类:
package io.demo;
public class ExecTest {
public static void main(String[] args) {
new Menu();
}
}
JavaIO范例:投票程序
有一个班采用明主投票的方法推选班长,班长候选人一共有4位,每个人的姓名和代号分别是:张三,1;李四,2;王五,3;赵六,4.程序操作员将每张选票上所选的代号(1、2、3、4)循环输入电脑,输入数字0表示输入结束,然后将所有候选人的得票情况显示出来:学生类Student:
package io.demo2;
public class Student implements Comparable<Student> {
private int stuNo;
private String name;
private int vote;
public Student(int stuNo, String name, int vote) {
super();
this.stuNo = stuNo;
this.name = name;
this.vote = vote;
}
@Override
public String toString() {
return stuNo + "\t" + name + "\t【" + vote + "】";
}
public int getStuNo() {
return stuNo;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getVote() {
return vote;
}
public void setVote(int vote) {
this.vote = vote;
}
@Override
public int compareTo(Student o) {
if (this.vote < o.vote) {
return 1;
} else if (this.vote > o.vote) {
return -1;
} else {
return 0;
}
}
}
数据输入类:InputData
package io.demo2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputData {
private BufferedReader bufferedReader = null;
public InputData() {
this.bufferedReader = new BufferedReader(new InputStreamReader(
System.in));
}
public String getString(String info) {
String temp = null;
System.out.println(info);
try {
temp = this.bufferedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return temp;
}
public int getInt(String info, String err) {
int temp = 0;
String str = null;
boolean flag = true;
while (flag) {
str = this.getString(info);
if (str.matches("\\d+")) {
temp = Integer.parseInt(str);
flag = false;
} else {
System.out.println(err);
}
}
return temp;
}
}
具体操作类:
package io.demo2;
import java.util.Arrays;
public class Operate {
Student[] students = { new Student(1, "张三", 0), new Student(2, "李四", 0),
new Student(3, "王五", 0), new Student(4, "赵六", 0) };
private boolean flag = true;
public Operate(){
this.printInfo(); //投票之前
while (flag) {
this.vote();
}
this.getResult();
this.printInfo(); //投票之后
System.out.println("系统退出!");
System.exit(0);
}
public void getResult(){
Arrays.sort(this.students);
System.out.println("投票最终结果:"+this.students[0].getName()+"同学以"+this.students[0].getVote()+"票领先!详细信息如下:");
}
public void vote(){
InputData inputData = new InputData();
int num = inputData.getInt("请输入班长候选人代号(数字0结束)", "此选票无效,请输入正确的候选人编号!");
switch (num) {
case 0:
this.flag = false;
break;
case 1:
this.students[0].setVote(this.students[0].getVote()+1);
break;
case 2:
this.students[1].setVote(this.students[1].getVote()+1);
break;
case 3:
this.students[2].setVote(this.students[2].getVote()+1);
break;
case 4:
this.students[3].setVote(this.students[3].getVote()+1);
break;
default:
System.out.println("此选票无效,请输入正确的候选人代号!");
break;
}
}
public void printInfo() {
System.out.println("编号\t姓名\t票数");
for (Student student : students) {
System.out.println(student);
}
}
}
测试类:
package io.demo2;
public class Exec {
public static void main(String[] args) {
new Operate();
}
}
java中的输入输出重定向
import java.util.Scanner;
public class InputRedirectDemo {
public static void main(String[] args) {
System.out.println("输入整数:");
Scanner scanner = new Scanner(System.in);
int sum = 0;
while (scanner.hasNextInt()) {
sum += scanner.nextInt();
}
System.out.println("sum = " + sum);
}
}
也可以从文件中读取整数计算它们的和。使用重定向从文件中读取整数:java InputRedirectDemo< integers.txt
类似的还可以使用输出重定向,也可以同时使用两种重定向: