现在的位置: 首页 > 综合 > 正文

【Java】输入与输出与JDK1.5之后的新型字符串StringBuilder

2018年05月06日 ⁄ 综合 ⁄ 共 6577字 ⁄ 字号 评论关闭

输入与输出在Java里面相当基础,在Java各大书籍里面讲了又讲,但上面的概念往往讲得非常复杂,Java的老师强调学生必须透彻地弄得每一个类、每一个方法的意义,实际上,我们仅仅关注的是如何达到一个简单的输入输出效果。在网络上一个小小的Java输入输出包罗万象,主要是在JDK1.5推出了新型的Scanner输入,而以往的BufferedReader同样可以完成输入操作,也许多有经验的老手把自己使用惯的一套放上网络,根本不告诉别人怎么修改。下面举例子,彻底地说明白Java的输入输出,包括控制台,包括文件,其实根本就不难,完全是有迹可循。

一、基本目标

首先在C盘有个a.txt,里面存在一些内容

接着,我将写如下的一个Java小程序来说明Java的输入与输出,首先同时利用BufferReader与Scanner获取用户输入的一行东西,以说明两个方法的同理性,Scanner只不过是BufferReader的改进而已,其次利用Scanner获取用户输入的一堆东西,同时存放在一个动态数组ArrayList里面,方便以后操作,不是网上那种程序都不知道怎么操作这一堆东西。动态数组ArrayList不明白的,可以参考我之前写的《【Java】Java中的Collections类——Java中升级版的数据结构》(点击打开链接),最后把上面那个a.txt读取到Java中新型的字符串StringBuilder里面来,之后把字符串中的所有回车替换成空格,再输出到C盘的b.txt:

二、制作过程

1、首先是同时利用BufferReader与Scanner获取用户输入的一行东西,以说明两个方法的同理性,但做之前你必须在引入以下两个包:

import java.util.*;
import java.io.*;

Scanner在util里面,BufferReader在io里面,而且下面的动态数组什么的都需要这些,之后才开始工作:

public static void inputOneLine() throws IOException{
	//System.in实际上与System.out互相对应,
	//System.in是指用户在控制台的输入,System.out是值控制台的输出
	System.out.print("请输入一行东西:");
	String inputString="";
	//Scanner对System.in进行读取,nextLine()读取一行,也就是读到第一个回车为止
	inputString=new Scanner(System.in).nextLine();		
	System.out.println("你输入的是:"+inputString);
	System.out.print("请输入一行东西:");
	//BufferedReader的readLine()同理
	inputString=new BufferedReader(new InputStreamReader(System.in)).readLine();
	System.out.println("你输入的是:"+inputString);
}

(1)值得注意的是,如果扫描器Scanner还有一个next()方法,这个方法是读到第一个分隔符位置,也就是如果遇到Tab、空格、回车,Scanner就会停止读写,而缓冲区读者BufferedReader同样有一个read()方法,这个方法只能读取一个字符,读完就停止了。

(2)缓冲区读者BufferedReader必须对输入流进行操作,也就是System.in必须被转换成一个输入流才能被缓冲区读者操作,扫描器Scanner则不用,可以之前对System.in操作,所以说Scanner是进步的

(3)Scanner里面还有nextInt();等方法,它是指如果用户输入的东西是整形int,就能自动返回这个int,不用再处理,一般没有人使用这些方法,因为要增加程序的容错性、健壮性,把所有东西都认为是字符串读进来,再进行是否数的判断,再转换为一个数。

2、其次利用Scanner获取用户输入的一堆东西,同时存放在一个动态数组ArrayList里面,方便以后操作。

public static void inputMultiLine(){
	//创建一个动态数组
	ArrayList<String> inputStringArr=new ArrayList<String>();
	System.out.println("请输入一堆东西,输入#结束");
	Scanner scanner=new Scanner(System.in);
	//这个循环不断继续,直到读进来的字符串是"#"才打断
	//由于Java中(好像不止是在Java,在不少语言都是),字符串是个对象,因此,只能使用equals方法判断
	//==,!=编译不出错,程序不错,但照样跑,因为对象与对象的==的意思是判断这两个是否都是String对象,不是这样的!
	while(true){
		String temp=scanner.nextLine();
		//如果字符串不是什么都没有,不是#
		if(!temp.equals("")&&!temp.equals("#")){
			//那么就把它压进动态数组
			inputStringArr.add(temp);
		}
		//如果是#则打断循环
		if(temp.equals("#")){
			break;
		}			
	}
	System.out.println("刚才,你输入的东西为"+inputStringArr);
	//如果动态数组存在第二个函数,则把它取出并打印出来
	if(inputStringArr.size()>1){
		System.out.println("你输入的第二行为:"+inputStringArr.get(1));
	}
}

3、最后把上面那个a.txt读取到Java中新型的字符串StringBuilder里面来,之后把字符串中的所有回车替换成空格,再输出到C盘的b.txt。

这里其实把扫描器要扫描的东西,从System.in改成一个文件就行了,这个方法由于设置到文件的输入输出,所以要跑出IO异常,至于缓冲区的读者写者在之前的《【Java】打印流与缓冲区读者完成输入与输出到文件操作》(点击打开链接)做过了,这里不做了。

public static void fileInputOutput() throws IOException{		
	//说明我要扫描c:\a.txt,在字符串的\必须转义成\\
	Scanner scanner=new Scanner(new File("c:\\a.txt"));
	StringBuilder filetoStringTemp=new StringBuilder("");
	//如果还有下一行的话?hasNext()方法不会导致扫描器Scanner的游标向下跳,因此可以作为判断条件
	//如果会向下跳就会出现隔行没有被读取的现象
	while(scanner.hasNext()){
		//StringBuilder没有重载运算符+=号,只能通过append()方法操作,同样的结果
		filetoStringTemp.append(scanner.next());
		//每读完一行,再补上一个换行,scanner不会把换行读进来
		filetoStringTemp.append("\n");
	}
	//把StringBuilder转换成String,同样也可以通过其toString实现。
	String filetoString=new String(filetoStringTemp);
	System.out.println(filetoString);
	//把所有回车换成空格,注意的是replaceAll是返回一个String,必须用来替换原来的字符串,
	//它不是一个void()方法,弄完就完事了
	filetoString=filetoString.replaceAll("\n", " ");
	System.out.println(filetoString);
	//判断这个字符串是否以"# "可以看到运行结果返回true,这方法在判断后缀名的时候很有用
	System.out.println(filetoString.endsWith("# "));
	//用打印流打印到文件,这里指定文件用文件写者来指定,这样就不会出现覆盖输出的问题了
	PrintWriter printwriter=new PrintWriter(new FileWriter("c:\\b.txt",true));
	//跟System.out.println()控制台输出方法有异曲同工之妙,只是我是输出到文件而已
	//把下面这行代码倒过来看你就能理解
	printwriter.println(filetoString);
	//必须关闭文件打印流才能完成一次输出,否则,打印的内容永远只在内存!
	printwriter.close();
	System.out.println("已经把字符串filetoString输出到c盘的b.txt里面了。");
}

(1)开始先用JDK1.5之后的新型字符串StringBuilder来不停地接受从文件读过来的东西。这个东西比String好,坦诚String同样可以接受字符串,程序还更短:

String a="";
a+="";

但是这样据说会多出很多临时变量让Java回收,效率不高,遇到一些超长的字符串,最好使用JDK1.5之后的新型字符串StringBuilder,这东西效率高,此外JDK1.5还新增了StringBuffer字符串,但这东西由于里面有线程互斥保护机制,所以效率没StringBuilder高,但如果出现多线程操作同一个字符串,使用StringBuffer你就不用写一段线程互斥的代码,线程互斥是什么,之前在《【Java】线程并发、互斥与同步》(点击打开链接)已经说过了。

(2)字符串里面还有indexof与substring的实用方法,曾经在《【Java】截取字符串中的首个图片地址》(点击打开链接)做过了,不再赘述。

三、总结与展望

于是,整个程序如下,在主函数调用上面的三个方法就能够直接执行了,这些方法必须定义为静态方法,才能被这样调用:

import java.util.*;
import java.io.*;

public class ScannerTest {
	public static void inputOneLine() throws IOException {
		// System.in实际上与System.out互相对应,
		// System.in是指用户在控制台的输入,System.out是值控制台的输出
		System.out.print("请输入一行东西:");
		String inputString = "";
		// Scanner对System.in进行读取,nextLine()读取一行,也就是读到第一个回车为止
		inputString = new Scanner(System.in).nextLine();
		System.out.println("你输入的是:" + inputString);
		System.out.print("请输入一行东西:");
		// BufferedReader的readLine()同理
		inputString = new BufferedReader(new InputStreamReader(System.in))
				.readLine();
		System.out.println("你输入的是:" + inputString);
	}

	public static void inputMultiLine() {
		// 创建一个动态数组
		ArrayList<String> inputStringArr = new ArrayList<String>();
		System.out.println("请输入一堆东西,输入#结束");
		Scanner scanner = new Scanner(System.in);
		// 这个循环不断继续,直到读进来的字符串是"#"才打断
		// 由于Java中(好像不止是在Java,在不少语言都是),字符串是个对象,因此,只能使用equals方法判断
		// ==,!=编译不出错,程序不错,但照样跑,因为对象与对象的==的意思是判断这两个是否都是String对象,不是这样的!
		while (true) {
			String temp = scanner.nextLine();
			// 如果字符串不是什么都没有,不是#
			if (!temp.equals("") && !temp.equals("#")) {
				// 那么就把它压进动态数组
				inputStringArr.add(temp);
			}
			// 如果是#则打断循环
			if (temp.equals("#")) {
				break;
			}
		}
		System.out.println("刚才,你输入的东西为" + inputStringArr);
		// 如果动态数组存在第二个函数,则把它取出并打印出来
		if (inputStringArr.size() > 1) {
			System.out.println("你输入的第二行为:" + inputStringArr.get(1));
		}
	}

	public static void fileInputOutput() throws IOException {
		// 说明我要扫描c:\a.txt,在字符串的\必须转义成\\
		Scanner scanner = new Scanner(new File("c:\\a.txt"));
		StringBuilder filetoStringTemp = new StringBuilder("");
		// 如果还有下一行的话?hasNext()方法不会导致扫描器Scanner的游标向下跳,因此可以作为判断条件
		// 如果会向下跳就会出现隔行没有被读取的现象
		while (scanner.hasNext()) {
			// StringBuilder没有重载运算符+=号,只能通过append()方法操作,同样的结果
			filetoStringTemp.append(scanner.next());
			// 每读完一行,再补上一个换行,scanner不会把换行读进来
			filetoStringTemp.append("\n");
		}
		// 把StringBuilder转换成String,同样也可以通过其toString实现。
		String filetoString = new String(filetoStringTemp);
		System.out.println(filetoString);
		// 把所有回车换成空格,注意的是replaceAll是返回一个String,必须用来替换原来的字符串,
		// 它不是一个void()方法,弄完就完事了
		filetoString = filetoString.replaceAll("\n", " ");
		System.out.println(filetoString);
		// 判断这个字符串是否以"# "可以看到运行结果返回true,这方法在判断后缀名的时候很有用
		System.out.println(filetoString.endsWith("# "));
		// 用打印流打印到文件,这里指定文件用文件写者来指定,这样就不会出现覆盖输出的问题了
		PrintWriter printwriter = new PrintWriter(new FileWriter("c:\\b.txt",
				true));
		// 跟System.out.println()控制台输出方法有异曲同工之妙,只是我是输出到文件而已
		// 把下面这行代码倒过来看你就能理解
		printwriter.println(filetoString);
		// 必须关闭文件打印流才能完成一次输出,否则,打印的内容永远只在内存!
		printwriter.close();
		System.out.println("已经把字符串filetoString输出到c盘的b.txt里面了。");
	}

	public static void main(String[] args) throws IOException {
		inputOneLine();
		inputMultiLine();
		fileInputOutput();
	}
}

抱歉!评论已关闭.