http://vaero.blog.51cto.com/4350852/809873
Android TTS实现简单阅读器
简单的Txt文本阅读器,主要用于介绍Google Android的TTS接口。
在package android.speech.tts内,主要阅读下TextToSpeech.OnInitListener、TextToSpeech. OnUtteranceCompletedListener两个接口和TextToSpeech、TextToSpeech.Engine两个类。
总之呢,我用的是讯飞语音TTS v1.0。有两个文件,一个是Service程序,一个是语音数据。下载网址:http://soft.shouji.com.cn/down/22160.html
布局由main.xml includes header.xml & footer.xml组成,并写有了定时收起等。
- /**
- * 1)本类用于main.xml的布局控制。子类再去实现各控件的TTS相关功能。
- * 2)用继承方式实现是为了利用布局中控件的onClick属性(懒得多写代码==!)。
- */
- public abstract class TtsFatherActivity extends Activity {
- private GestureDetector gd; // 手势检测
- private GlobalUtil globalUtil; // 全局公用类
- private ScrollView scrollView; // 滚动视图
- private LinearLayout headerLayout, footerLayout; // 顶部、底部布局
- private TextView textView; // 文本标签
- private static final long ANIM_DURATION = 500; // 动画时间(毫秒)
- private static final int DIALOG_TEXT_LIST = 0; // 文本列表对话框id
- private final String[] textPaths = new String[] { "one.txt", "two.txt",
- "浏览..." }; // assets内文本资源路径
- protected String textTitle; // 文本标题
- protected String textContent; // 文本内容
- private Timer timer; // 计时器
- private static final long TIMEOUT = 2000; // 超时时间
- private static final int TIMER_LAYOUT_OUT = 1; // 布局收起
- private boolean isLayoutOut = false; // 布局收起状态
- /** Handler处理操作 */
- public Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case TIMER_LAYOUT_OUT:
- /* headerLayout收起动画 */
- globalUtil.startTransAnim(headerLayout,
- GlobalUtil.AnimMode.UP_OUT, ANIM_DURATION);
- headerLayout.setVisibility(View.GONE);
- /* footerLayout收起动画 */
- globalUtil.startTransAnim(footerLayout,
- GlobalUtil.AnimMode.DOWN_OUT, ANIM_DURATION);
- footerLayout.setVisibility(View.GONE);
- isLayoutOut = true; // 重置布局收起状态
- break;
- }
- }
- };
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- gd = new GestureDetector(new MySimpleGesture()); // 手势检测处理
- globalUtil = GlobalUtil.getInstance(); // 获取全局公用类
- scrollView = (ScrollView) findViewById(R.id.scrollView); // 获取滚动视图
- headerLayout = (LinearLayout) findViewById(R.id.headerLayout); // 获取顶部布局
- footerLayout = (LinearLayout) findViewById(R.id.footerLayout); // 获取底部布局
- textView = (TextView) findViewById(R.id.textView);
- setText(0); // 默认显示“上邪.txt”
- newTimerLayoutOut(); // 定时收起布局
- }
- /** 使用GestureDetector检测手势(ScrollView内也需监听时的方式) */
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- gd.onTouchEvent(ev);
- scrollView.onTouchEvent(ev);
- return super.dispatchTouchEvent(ev);
- }
- /** onCreateDialog */
- @Override
- protected Dialog onCreateDialog(int id) {
- switch (id) {
- case DIALOG_TEXT_LIST:
- return new AlertDialog.Builder(this).setItems(textPaths,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (2 == which) {
- // 跳转到文件浏览Activity
- startActivityForResult(new Intent(
- TtsFatherActivity.this,
- FileBrowserActivity.class),
- FileBrowserActivity.CODE_FILE_BROWSER);
- } else {
- setText(which); // 设置文本内容
- }
- }
- }).create();
- }
- return super.onCreateDialog(id);
- }
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == FileBrowserActivity.CODE_FILE_BROWSER) {
- if (resultCode == RESULT_OK) {
- // 获得文件名称
- String filename = data.getExtras().getString(
- FileBrowserActivity.KEY_FILENAME);
- this.textTitle = filename;
- try {
- // FileInputStream fis = new FileInputStream(
- // new File(filename));
- // // FileInputStream不支持mark/reset操作,不该直接这样
- // String encoding = globalUtil.getIsEncoding(fis);
- // textContent = globalUtil.is2Str(fis, encoding);
- /**
- * TXT简单判断编码类型后转字符串
- *
- * ps:
- * 1)扯淡,3.58MB的txt读出来了==
- * 看来需要转成BufferedReader以readLine()方式读好些啊
- *
- * 2)TextView将大文本全部显示,这貌似...
- *
- * 时间主要花费在文本显示过程,不改进了,暂时将就吧==
- * 2.1)用View自定义个控件显示文本也蛮久的,未减少多少时间。
- * 2.2)至于AsyncTask,文本显示还是要在UI线程的==。
- *
- * 如果我们要仿个阅读器,用View自定义个控件还是必须的。
- * 1)分段读取大文本,可以考虑3段(前后两段用于缓冲)
- * 根据滑屏&显示内容等,注意文本显示衔接。
- * 2)滚动条可以外面套个ScrollView。由各属性判断出大文本需要显示的高度,
- * 重写onMeasure用setMeasuredDimension()设置好,才会有滚动条。
- * 当然自己用scrollTo()、scrollBy()实现动画也是好的。
- * 3)至于其他选中当前行啊什么的,慢慢写就成了...
- *
- * 不知道大家还有什么好的想法没?
- */
- // long time1 = System.currentTimeMillis();
- textContent = globalUtil.is2Str(new FileInputStream(
- new File(filename)));
- // long time2 = System.currentTimeMillis();
- // Log.e("TAG1", "==" + (time2 - time1) + "==");
- textView.setText(textContent);
- // long time3 = System.currentTimeMillis();
- // Log.e("TAG1", "==" + (time3 - time2) + "==");
- } catch (Exception e) {
- textView.setText(R.string.text_error);
- textContent = "";
- }
- }
- }
- }
- /** 设置文本内容 */
- private void setText(int textIndex) {
- this.textTitle = textPaths[textIndex];
- try {
- textContent = globalUtil.is2Str(getAssets().open(textTitle),
- "UTF-8");
- textView.setText(textContent);
- } catch (IOException e) {
- textView.setText(R.string.text_error);
- textContent = "";
- }
- }
- /** 定时收起布局(已定时时重新开始定时) */
- protected void newTimerLayoutOut() {
- if (null != timer) {
- timer.cancel();
- }
- timer = new Timer();
- // 超时TIMEOUT退出
- timer.schedule(new TimerTask() {
- @Override
- public void run() {
- mHandler.sendEmptyMessage(TIMER_LAYOUT_OUT);
- }
- }, TIMEOUT);
- }
- /** 自定义手势类 */
- private class MySimpleGesture extends SimpleOnGestureListener {
- /** 双击第二下 */
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- if (isLayoutOut) {
- /* headerLayout进入动画 */
- headerLayout.setVisibility(View.VISIBLE);
- globalUtil.startTransAnim(headerLayout,
- GlobalUtil.AnimMode.UP_IN, ANIM_DURATION);
- /* footerLayout进入动画 */
- footerLayout.setVisibility(View.VISIBLE);
- globalUtil.startTransAnim(footerLayout,
- GlobalUtil.AnimMode.DOWN_IN, ANIM_DURATION);
- newTimerLayoutOut(); // 定时收起布局
- isLayoutOut = false; // 重置布局收起状态
- } else {
- /* headerLayout退出动画 */
- globalUtil.startTransAnim(headerLayout,
- GlobalUtil.AnimMode.UP_OUT, ANIM_DURATION);
- headerLayout.setVisibility(View.GONE);
- /* footerLayout退出动画 */
- globalUtil.startTransAnim(footerLayout,
- GlobalUtil.AnimMode.DOWN_OUT, ANIM_DURATION);
- footerLayout.setVisibility(View.GONE);
- // 取消定时收起动画
- if (null != timer) {
- timer.cancel();
- }
- isLayoutOut = true; // 重置布局收起状态
- }
- return false;
- }
- /** 长按屏幕时 */
- @Override
- public void onLongPress(MotionEvent e) {
- // 显示文本列表对话框
- showDialog(DIALOG_TEXT_LIST);
- }
- }
- }
- public class TtsSampleActivity extends TtsFatherActivity implements
- OnSeekBarChangeListener, TextToSpeech.OnInitListener,
- TextToSpeech.OnUtteranceCompletedListener {
- // private static final String TAG = "TtsSampleActivity"; // 日志标记
- private AudioManager audioManager; // 音频管理对象
- // TTS音量类型(AudioManager.STREAM_MUSIC = AudioManager.STREAM_TTS = 11)
- private static final int STREAM_TTS = AudioManager.STREAM_MUSIC;
- private TextToSpeech mTts; // TTS对象
- private static final int REQ_CHECK_TTS_DATA = 110; // TTS数据校验请求值
- private boolean isSetting = false; // 进入设置标记
- private boolean isRateChanged = false; // 速率改变标记
- private boolean isStopped = false; // TTS引擎停止发声标记
- private float mSpeechRate = 1.0f; // 朗读速率
- private SeekBar volumeBar, speedBar; // 音量&语速
- // 合成声音资源文件的路径
- private static final String SAVE_DIR_PATH = "/sdcard/AndroidTTS/";
- private static final String SAVE_FILE_PATH = SAVE_DIR_PATH + "sound.wav";
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // 获得音频管理对象
- audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- /* volumeBar */
- volumeBar = (SeekBar) findViewById(R.id.volumeBar);
- volumeBar.setOnSeekBarChangeListener(this);
- // 由当前音量设置进度(需保证进度上限=音频上限=15,否则按比例设置)
- volumeBar.setProgress(audioManager.getStreamVolume(STREAM_TTS));
- /* speedBar */
- speedBar = (SeekBar) findViewById(R.id.speedBar);
- speedBar.setOnSeekBarChangeListener(this);
- initDirs(SAVE_DIR_PATH); // 初始化文件夹路径
- }
- /** saveFileBtn点击事件 */
- public void saveFile(View v) {
- // 将文本合成声音资源文件
- int resId = TextToSpeech.SUCCESS == ttsSaveFile(textContent,
- SAVE_FILE_PATH) ? R.string.synt_success : R.string.synt_fail;
- Toast.makeText(this, resId, Toast.LENGTH_SHORT).show(); // Toast提示
- newTimerLayoutOut(); // 重新定时收起布局
- }
- /** playFileBtn点击事件 */
- public void playFile(View v) {
- ttsPlayFile(SAVE_FILE_PATH); // 播放指定的使用文件
- newTimerLayoutOut(); // 重新定时收起布局
- }
- /** stopBtn点击事件 */
- public void stop(View v) {
- ttsStop(); // 停止当前发声
- newTimerLayoutOut(); // 重新定时收起布局
- }
- /** playBtn点击事件 */
- public void play(View v) {
- ttsPlay(); // tts合成语音播放
- newTimerLayoutOut(); // 重新定时收起布局
- }
- /** settingBtn点击事件 */
- public void setting(View v) {
- // 跳转到“语音输入与输出”设置界面&设置标志位
- isSetting = toTtsSettings();
- newTimerLayoutOut(); // 重新定时收起布局
- }
- /** SeekBar进度改变时 */
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser) {
- switch (seekBar.getId()) {
- case R.id.volumeBar:
- // 由设置当前TTS音量(需保证进度上限=音频上限=15,否则按比例设置)
- audioManager.setStreamVolume(STREAM_TTS, progress, 0);
- break;
- case R.id.speedBar:
- /* 需要重新绑定TTS引擎,速度在onInit()里设置 */
- isRateChanged = true; // 速率改变标记
- // 最大值为20时,以下方式计算为0.5~2倍速
- mSpeechRate = (progress >= 10) ? (progress / 10f)
- : (0.5f + progress / 20f);
- // 校验TTS引擎安装及资源状态,重新绑定引擎
- checkTtsData();
- break;
- }
- newTimerLayoutOut(); // 重新定时收起布局
- }
- /** SeekBar开始拖动时 */
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
- /** SeekBar结束拖动时 */
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- /**
- * TTS引擎初始化时回调方法
- *
- * 引擎相关参数(音量、语速)等都需在这设置。
- * 1)创建完成后再去设置,会有意外的效果^^
- * 2)音量也可由AudioManager进行控制(和音乐一个媒体流类型)
- */
- @Override
- public void onInit(int status) {
- if (status == TextToSpeech.SUCCESS) {
- mTts.setSpeechRate(mSpeechRate); // 设置朗读速率
- // 设置发声合成监听,注意也需要在onInit()中做才有效
- mTts.setOnUtteranceCompletedListener(this);
- if (isRateChanged) {
- ttsPlay(); // tts合成语音播放
- isRateChanged = false; // 重置标记位
- }
- }
- }
- /**
- * TTS引擎完成发声完成时回调方法
- *
- * 1)stop()取消时也会回调
- * 2)需在onInit()内设置接口
- * 3)utteranceId由speak()时的请求参数设定
- * 参数key:TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID
- */
- @Override
- public void onUtteranceCompleted(final String utteranceId) {
- /* 测试该接口的Toast提示 */
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- int resId = isStopped ? R.string.utte_stopped
- : R.string.utte_completed;
- // 提示文本发生完成
- Toast.makeText(getApplicationContext(),
- getString(resId, utteranceId), Toast.LENGTH_SHORT)
- .show();
- }
- });
- }
- /** onActivityResult */
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQ_CHECK_TTS_DATA) {
- switch (resultCode) {
- case TextToSpeech.Engine.CHECK_VOICE_DATA_PASS: // TTS引擎可用
- // 针对于重新绑定引擎,需要先shutdown()
- if (null != mTts) {
- ttsStop(); // 停止当前发声
- ttsShutDown(); // 释放资源
- }
- mTts = new TextToSpeech(this, this); // 创建TextToSpeech对象
- break;
- case TextToSpeech.Engine.CHECK_VOICE_DATA_BAD_DATA: // 数据错误
- case TextToSpeech.Engine.CHECK_VOICE_DATA_MISSING_DATA: // 缺失数据资源
- case TextToSpeech.Engine.CHECK_VOICE_DATA_MISSING_VOLUME: // 缺少数据存储量
- notifyReinstallDialog(); // 提示用户是否重装TTS引擎数据的对话框
- break;
- case TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL: // 检查失败
- default:
- break;
- }
- }
- super.onActivityResult(requestCode, resultCode, data);
- }
- /** 校验TTS引擎安装及资源状态 */
- private boolean checkTtsData() {
- try {
- Intent checkIntent = new Intent();
- checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
- startActivityForResult(checkIntent, REQ_CHECK_TTS_DATA);
- return true;
- } catch (ActivityNotFoundException e) {
- return false;
- }
- }
- /** 提示用户是否重装TTS引擎数据的对话框 */
- private void notifyReinstallDialog() {
- new AlertDialog.Builder(this).setTitle("TTS引擎数据错误")
- .setMessage("是否尝试重装TTS引擎数据到设备上?")
- .setPositiveButton("是", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // 触发引擎在TTS引擎在设备上安装资源文件
- Intent dataIntent = new Intent();
- dataIntent
- .setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
- startActivity(dataIntent);
- }
- }).setNegativeButton("否", null).show();
- }
- /** 跳转到“语音输入与输出”设置界面 */
- private boolean toTtsSettings() {
- try {
- startActivity(new Intent("com.android.settings.TTS_SETTINGS"));
- return true;
- } catch (ActivityNotFoundException e) {
- return false;
- }
- }
- @Override
- protected void onStart() {
- checkTtsData(); // 校验TTS引擎安装及资源状态
- super.onStart();
- }
- @Override
- protected void onResume() {
- /* 从设置返回后重新绑定TTS,避免仍用旧引擎 */
- if (isSetting) {
- checkTtsData(); // 校验TTS引擎安装及资源状态
- isSetting = false;
- }
- super.onResume();
- }
- @Override
- protected void onStop() {
- /* HOME键 */
- ttsStop(); // 停止当前发声
- super.onStop();
- }
- @Override
- public void onBackPressed() {
- /* BACK键 */
- ttsStop(); // 停止当前发声
- ttsShutDown(); // 释放资源
- super.onBackPressed();
- }
- /** tts合成语音播放 */
- private int ttsPlay() {
- if (null != mTts) {
- isStopped = false; // 设置标记
- /**
- * 叙述text。
- *
- * 1) 参数2(int queueMode)
- * 1.1)QUEUE_ADD:增加模式。增加在队列尾,继续原来的说话。
- * 1.2)QUEUE_FLUSH:刷新模式。中断正在进行的说话,说新的内容。
- * 2)参数3(HashMap<String, String> params)
- * 2.1)请求的参数,可以为null。
- * 2.2)注意KEY_PARAM_UTTERANCE_ID。
- */
- HashMap<String, String> params = new HashMap<String, String>();
- params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, textTitle);
- return mTts.speak(textContent, TextToSpeech.QUEUE_FLUSH, params);
- }
- return TextToSpeech.ERROR;
- }
- // /** 判断TTS是否正在发声 */
- // private boolean isSpeaking() {
- // // 使用mTts.isSpeaking()判断时,第一次speak()返回true,多次就返回false了。
- // return audioManager.isMusicActive();
- // }
- /** 停止当前发声,同时放弃所有在等待队列的发声 */
- private int ttsStop() {
- isStopped = true; // 设置标记
- return (null == mTts) ? TextToSpeech.ERROR : mTts.stop();
- }
- /** 释放资源(解除语音服务绑定) */
- private void ttsShutDown() {
- if (null != mTts) {
- mTts.shutdown();
- }
- }
- /** 初始化文件夹路径 */
- private void initDirs(final String dirpath) {
- File file = new File(dirpath);
- if (!file.exists()) {
- file.mkdirs();
- }
- }
- /** 将文本合成声音资源文件 */
- private int ttsSaveFile(String text, final String filename) {
- return (null == mTts) ? TextToSpeech.ERROR : mTts.synthesizeToFile(
- text, null, filename);
- }
- /** 播放指定的使用文件 */
- private int ttsPlayFile(final String filename) {
- // 如果存在FILENAME_SAVE文件的话
- if (new File(filename).exists()) {
- try {
- /* 使用MediaPlayer进行播放(没进行控制==) */
- MediaPlayer player = new MediaPlayer();
- player.setDataSource(filename);
- player.prepare();
- player.start();
- return TextToSpeech.SUCCESS;
- } catch (Exception e) {
- e.printStackTrace();
- return TextToSpeech.ERROR;
- }
- }
- return TextToSpeech.ERROR;
- }
- }
3)公共工具
- /**
- * @brief 全局公用类
- * @details 各部分公用内容都较少,就丢一起了==。
- */
- public final class GlobalUtil {
- /** Bob Lee懒加载:内部类GlobalUtilHolder */
- static class GlobalUtilHolder {
- static GlobalUtil instance = new GlobalUtil();
- }
- /** Bob Lee懒加载:返回GlobalUtil的单例 */
- public static GlobalUtil getInstance() {
- return GlobalUtilHolder.instance;
- }
- /** 获取窗口默认显示信息 */
- public Display getDisplay(Context mContext) {
- WindowManager wm = (WindowManager) mContext
- .getSystemService(Context.WINDOW_SERVICE);
- return wm.getDefaultDisplay();
- }
- /** 动画方式 */
- public enum AnimMode {
- UP_IN, UP_OUT, DOWN_IN, DOWN_OUT, LEFT_IN, LEFT_OUT, RIGHT_IN, RIGHT_OUT
- };
- /**
- * @brief 横移或竖移动画
- *
- * @param v 移动视图
- * @param animMode 动画方式
- * @param durationMillis 持续时间
- */
- public void startTransAnim(View v, AnimMode animMode, long durationMillis) {
- int w = v.getWidth(), h = v.getHeight(); // 获取移动视图宽高
- float fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0;
- switch (animMode) {
- case UP_IN:
- fromYDelta = -h;
- break;
- case UP_OUT:
- toYDelta = -h;
- break;
- case DOWN_IN:
- fromYDelta = h;
- break;
- case DOWN_OUT:
- toYDelta = h;
- break;
- case LEFT_IN:
- fromXDelta = -w;
- break;
- case LEFT_OUT:
- toXDelta = -w;
- break;
- case RIGHT_IN:
- fromXDelta = w;
- break;
- case RIGHT_OUT:
- toXDelta = w;
- break;
- }
- TranslateAnimation transAnim = new TranslateAnimation(fromXDelta,
- toXDelta, fromYDelta, toYDelta); // 位移动画
- transAnim.setDuration(durationMillis); // 设置时间
- v.startAnimation(transAnim); // 开始动画
- }
- /**
- * @brief InputStream转为String
- *
- * @param is 输入流
- * @param encoding 编码方式
- * @return 字符串结果
- * @throws UnsupportedEncodingException 不支持的编码
- */
- public String is2Str(InputStream is, String encoding)
- throws UnsupportedEncodingException {
- /*
- * 不直接从InputStream里读byte[],再转成String,以避免截断汉字。
- * 如utf8一个汉字3字节,用byte[1024]会截断末尾而乱码。
- */
- InputStreamReader isReader = new InputStreamReader(is, encoding);
- /* 以char[]方式读取 */
- StringBuffer out = new StringBuffer();
- try {
- char[] b = new char[4096]; // 1024*4*2Byte
- for (int n; (n = isReader.read(b)) != -1;) {
- out.append(b, 0, n);
- }
- return out.toString();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "";
- }
- /**
- * @brief 带BOM的文本的FileInputStream转为String,自动判断编码类型
- *
- * @param fis 文件输入流
- * @return 字符串结果
- * @throws UnsupportedEncodingException 不支持的编码
- */
- public String is2Str(FileInputStream fis)
- throws UnsupportedEncodingException {
- // 转成BufferedInputStream
- BufferedInputStream bis = new BufferedInputStream(fis);
- // 简单判断文本编码
- String encoding = getIsEncoding(bis);
- // 转成BufferedReader
- BufferedReader reader = new BufferedReader(new InputStreamReader(bis,
- encoding));
- /* 以readLine()方式读取 */
- StringBuffer out = new StringBuffer();
- try {
- for (String s; (s = reader.readLine()) != null;) {
- out.append(s);
- out.append("\n");
- }
- return out.toString();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "";
- }
- /**
- * @brief 带BOM的文本判断,否则认为GB2312(即ANSI类型的TXT)
- * @details 复杂文件编码检测,请google cpdetector!
- *
- * @param is InputStream
- * @return 编码类型
- *
- * @warning markSupported为true时才进行判断,否则返回默认GB2312。
- * \n FileInputStream不支持mark/reset操作;BufferedInputStream支持此操作。
- */
- public String getIsEncoding(InputStream is) {
- String code = "GB2312";
- // Log.e("is.markSupported()", "==" + is.markSupported() + "==");
- if (is.markSupported()) { // 支持mark()
- try {
- is.mark(5); // 打个TAG(5>3)
- byte[] head = new byte[3];
- is.read(head);
- if (head[0] == -1 && head[1] == -2)
- code = "UTF-16";
- if (head[0] == -2 && head[1] == -1)
- code = "Unicode";
- if (head[0] == -17 && head[1] == -69 && head[2] == -65)
- code = "UTF-8";
- is.reset(); // 返回TAG
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return code;
- }
- }
直接读大文本,后果自负啊。(没做控制呢T^T)