现在越来越多手机支持OTG功能,通过OTG可以实现与外接入的U盘等USB设备实现数据传输。关于OTG,可以参考:
http://blog.csdn.net/srw11/article/details/39154053。
最近项目上用到了该功能,项目上用的是安卓7.1的盒子,要实现与插入的U盘进行数据操作。通过大量的找资料,终于实现了项目上需要的功能。找资料主要是解决两个问题:
  1. U盘权限问题
  2. U盘文件路径及文件操作

    废话不多说,感觉还是喜欢直接上代码才爽快。项目中用到了一个开源框架,开源地址是: 
    https://github.com/magnusja/libaums


代码部分:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
//输入的内容
private EditText u_disk_edt;
//写入到U盘
private Button u_disk_write;
//从U盘读取
private Button u_disk_read;
//显示读取的内容
private TextView u_disk_show;
//自定义U盘读写权限
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
//当前处接U盘列表
private UsbMassStorageDevice[] storageDevices;
//当前U盘所在文件目录
private UsbFile cFolder;
private final static String U_DISK_FILE_NAME = "u_disk.txt";
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case :
showToastMsg("保存成功");
break;
case :
String txt = msg.obj.toString();
if (!TextUtils.isEmpty(txt))
u_disk_show.setText("读取到的数据是:" + txt);
break;
}
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
} private void initViews() {
u_disk_edt = (EditText) findViewById(R.id.u_disk_edt);
u_disk_write = (Button) findViewById(R.id.u_disk_write);
u_disk_read = (Button) findViewById(R.id.u_disk_read);
u_disk_show = (TextView) findViewById(R.id.u_disk_show);
u_disk_write.setOnClickListener(this);
u_disk_read.setOnClickListener(this);
} @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.u_disk_write:
final String content = u_disk_edt.getText().toString().trim();
mHandler.post(new Runnable() {
@Override
public void run() {
saveText2UDisk(content);
}
}); break;
case R.id.u_disk_read:
mHandler.post(new Runnable() {
@Override
public void run() {
readFromUDisk();
}
}); break;
}
} private void readFromUDisk() {
UsbFile[] usbFiles = new UsbFile[];
try {
usbFiles = cFolder.listFiles();
} catch (IOException e) {
e.printStackTrace();
}
if (null != usbFiles && usbFiles.length > ) {
for (UsbFile usbFile : usbFiles) {
if (usbFile.getName().equals(U_DISK_FILE_NAME)) {
readTxtFromUDisk(usbFile);
}
}
}
} /**
* @description 保存数据到U盘,目前是保存到根目录的
* @author ldm
* @time 2017/9/1 17:17
*/
private void saveText2UDisk(String content) {
//项目中也把文件保存在了SD卡,其实可以直接把文本读取到U盘指定文件
File file = FileUtil.getSaveFile(getPackageName()
+ File.separator + FileUtil.DEFAULT_BIN_DIR,
U_DISK_FILE_NAME);
try {
FileWriter fw = new FileWriter(file);
fw.write(content);
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
if (null != cFolder) {
FileUtil.saveSDFile2OTG(file, cFolder);
mHandler.sendEmptyMessage();
}
} /**
* @description OTG广播注册
* @author ldm
* @time 2017/9/1 17:19
*/
private void registerUDiskReceiver() {
//监听otg插入 拔出
IntentFilter usbDeviceStateFilter = new IntentFilter();
usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(mOtgReceiver, usbDeviceStateFilter);
//注册监听自定义广播
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mOtgReceiver, filter);
} /**
* @description OTG广播,监听U盘的插入及拔出
* @author ldm
* @time 2017/9/1 17:20
* @param
*/
private BroadcastReceiver mOtgReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case ACTION_USB_PERMISSION://接受到自定义广播
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
//允许权限申请
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (usbDevice != null) {
//用户已授权,可以进行读取操作
readDevice(getUsbMass(usbDevice));
} else {
showToastMsg("没有插入U盘");
}
} else {
showToastMsg("未获取到U盘权限");
}
break;
case UsbManager.ACTION_USB_DEVICE_ATTACHED://接收到U盘设备插入广播
UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device_add != null) {
//接收到U盘插入广播,尝试读取U盘设备数据
redUDiskDevsList();
}
break;
case UsbManager.ACTION_USB_DEVICE_DETACHED://接收到U盘设设备拔出广播
showToastMsg("U盘已拔出");
break;
}
}
}; /**
* @description U盘设备读取
* @author ldm
* @time 2017/9/1 17:20
*/
private void redUDiskDevsList() {
//设备管理器
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
//获取U盘存储设备
storageDevices = UsbMassStorageDevice.getMassStorageDevices(this);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, , new Intent(ACTION_USB_PERMISSION), );
//一般手机只有1个OTG插口
for (UsbMassStorageDevice device : storageDevices) {
//读取设备是否有权限
if (usbManager.hasPermission(device.getUsbDevice())) {
readDevice(device);
} else {
//没有权限,进行申请
usbManager.requestPermission(device.getUsbDevice(), pendingIntent);
}
}
if (storageDevices.length == ) {
showToastMsg("请插入可用的U盘");
}
} private UsbMassStorageDevice getUsbMass(UsbDevice usbDevice) {
for (UsbMassStorageDevice device : storageDevices) {
if (usbDevice.equals(device.getUsbDevice())) {
return device;
}
}
return null;
} private void readDevice(UsbMassStorageDevice device) {
try {
device.init();//初始化
//设备分区
Partition partition = device.getPartitions().get();
//文件系统
FileSystem currentFs = partition.getFileSystem();
currentFs.getVolumeLabel();//可以获取到设备的标识
//通过FileSystem可以获取当前U盘的一些存储信息,包括剩余空间大小,容量等等
Log.e("Capacity: ", currentFs.getCapacity() + "");
Log.e("Occupied Space: ", currentFs.getOccupiedSpace() + "");
Log.e("Free Space: ", currentFs.getFreeSpace() + "");
Log.e("Chunk size: ", currentFs.getChunkSize() + "");
cFolder = currentFs.getRootDirectory();//设置当前文件对象为根目录
} catch (Exception e) {
e.printStackTrace();
}
} private void showToastMsg(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
} private void readTxtFromUDisk(UsbFile usbFile) {
UsbFile descFile = usbFile;
//读取文件内容
InputStream is = new UsbFileInputStream(descFile);
//读取秘钥中的数据进行匹配
StringBuilder sb = new StringBuilder();
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(is));
String read;
while ((read = bufferedReader.readLine()) != null) {
sb.append(read);
}
Message msg = mHandler.obtainMessage();
msg.what = ;
msg.obj = read;
mHandler.sendMessage(msg);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

对应布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ldm.androidudisk.MainActivity"
android:orientation="vertical"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android盒子外接U盘文件读写测试DEMO"
android:layout_gravity="center"
android:layout_margin="10dp"
/> <EditText
android:id="@+id/u_disk_edt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:hint="输入要保存到U盘中的文字内容"/> <Button
android:id="@+id/u_disk_write"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:text="往U盘中写入数据"/> <Button
android:id="@+id/u_disk_read"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:text="从U盘中读取数据"/> <TextView
android:id="@+id/u_disk_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
/>
</LinearLayout>

文件操作工具类:

package com.ldm.androidudisk.utils;

import android.os.Environment;

import com.github.mjdev.libaums.fs.UsbFile;
import com.github.mjdev.libaums.fs.UsbFileOutputStream; import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import static android.os.Environment.getExternalStorageDirectory; /**
* 文件操作工具类
*
* @author ldm
* @description:
* @date 2016-4-28 下午3:17:10
*/
public final class FileUtil {
public static final String DEFAULT_BIN_DIR = "usb"; /**
* 检测SD卡是否存在
*/
public static boolean checkSDcard() {
return Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState());
} /**
* 从指定文件夹获取文件
*
* @return 如果文件不存在则创建, 如果如果无法创建文件或文件名为空则返回null
*/
public static File getSaveFile(String folderPath, String fileNmae) {
File file = new File(getSavePath(folderPath) + File.separator
+ fileNmae);
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
return file;
} /**
* 获取SD卡下指定文件夹的绝对路径
*
* @return 返回SD卡下的指定文件夹的绝对路径
*/
public static String getSavePath(String folderName) {
return getSaveFolder(folderName).getAbsolutePath();
} /**
* 获取文件夹对象
*
* @return 返回SD卡下的指定文件夹对象,若文件夹不存在则创建
*/
public static File getSaveFolder(String folderName) {
File file = new File(getExternalStorageDirectory()
.getAbsoluteFile()
+ File.separator
+ folderName
+ File.separator);
file.mkdirs();
return file;
} /**
* 关闭流
*/
public static void closeIO(Closeable... closeables) {
if (null == closeables || closeables.length <= ) {
return;
}
for (Closeable cb : closeables) {
try {
if (null == cb) {
continue;
}
cb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} private static void redFileStream(OutputStream os, InputStream is) throws IOException {
int bytesRead = ;
byte[] buffer = new byte[ * ];
while ((bytesRead = is.read(buffer)) != -) {
os.write(buffer, , bytesRead);
}
os.flush();
os.close();
is.close();
} /**
* @description 把本地文件写入到U盘中
* @author ldm
* @time 2017/8/22 10:22
*/
public static void saveSDFile2OTG(final File f, final UsbFile usbFile) {
UsbFile uFile = null;
FileInputStream fis = null;
try {//开始写入
fis = new FileInputStream(f);//读取选择的文件的
if (usbFile.isDirectory()) {//如果选择是个文件夹
UsbFile[] usbFiles = usbFile.listFiles();
if (usbFiles != null && usbFiles.length > ) {
for (UsbFile file : usbFiles) {
if (file.getName().equals(f.getName())) {
file.delete();
}
}
}
uFile = usbFile.createFile(f.getName());
UsbFileOutputStream uos = new UsbFileOutputStream(uFile);
try {
redFileStream(uos, fis);
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (final Exception e) {
e.printStackTrace();
}
}
}

不要忘记在app/build.grade下添加:

compile 'com.github.mjdev:libaums:0.5.5'

及AndroidManifest.xml中添加权限:

  <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
												

Android设备与外接U盘实现数据读取操作的更多相关文章

  1. 如何查看USB方式连接Android设备的外接设备信息

    1,USB存储设备(如:U盘,移动硬盘): //USB存储设备 插拔监听与 SD卡插拔监听一致. private USBBroadCastReceiver mBroadcastReceiver; In ...

  2. Android+Servlet+MySql+JSON实现简单的数据查询操作--C/S架构

    本例简单地实现Android客户端与服务器端交互,主要是通过客户端输入内容(学号)提交到服务器端,服务器端与数据库交互去查询相应信息(姓名).根据这个做个完整的安卓登录是没问题的.本例数据库服务器都采 ...

  3. MySQL Explain命令详解--表的读取顺序,数据读取操作的类型等

    表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的) 不损失精确 ...

  4. Android后门GhostCtrl,完美控制设备任意权限并窃取用户数据

    Android系统似乎已经成为世界各地病毒作者的首选目标,每天都有新的恶意软件在感染更多的设备. 这一次,安全公司趋势科技发布警告,他们发现了一个新的Android后门--GhostCtrl Ghos ...

  5. android开发中的5种存储数据方式

    数据存储在开发中是使用最频繁的,根据不同的情况选择不同的存储数据方式对于提高开发效率很有帮助.下面笔者在主要介绍Android平台中实现数据存储的5种方式. 1.使用SharedPreferences ...

  6. 非root Android设备上Tcpdump的实现

    通常我们在Android应用中执行某个命令时会使用"Runtime.getRuntime().exec("命令路径")"这种方式,但是当我们执行抓包操作时,使用 ...

  7. 在ios android设备上使用 Protobuf (使用dll方式)

    http://game.ceeger.com/forum/read.php?tid=13479 如果你的工程可以以.Net 2.0 subset模式运行,请看这个帖子中的方法. 地址:http://g ...

  8. android设备休眠机制

    如果一开始就对Android手机的硬件架构有一定的了解,设计出的应用程序通常不会成为待机电池杀手,而要设计出正确的通信机制与通信协议也并不困难.但如果不去了解而盲目设计,可就没准了. 首先Androi ...

  9. Android判断当前的android设备是否处于联网状态

    首先,要想获得当前android设备是否处于联网状态,那么android本身给我们提供了一个服务 private ConnectivityManager connectivityManager;//用 ...

随机推荐

  1. 算法 Tricks(三)—— 数组(序列)任意区间最小(大)值

    序列(数组)的区间通过左右端点确定,这样首先设置一个最值变量用来记录最值,从左端点一步步移动到右端点,自然移动的过程中也可以计算整个区间的和,也即一次线性遍历下来,可同时获得多个有用信息. // 区间 ...

  2. vue-cli 构建vue项目

    师父说,咱们还是要用vue-cli 去构建前端项目.然后我就开始了 懵逼之旅. 今天上午主要就是搞懂用webpack和vue-cli怎么搭建 运行项目 首先找到了咱们博客园 园友的博客,提供了大概五个 ...

  3. Can't bind to 'formGroup' since it isn't a known property of 'form'

    在APP.module.ts中引入FormsModule, ReactiveFormsModule. import { BrowserModule } from '@angular/platform- ...

  4. zoj 2724 Windows Message Queue 优先队列

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1724 题目大意: 给出两种操作,GET要求取出当前队首的元素,而PUT会输入名 ...

  5. 5、qq物联开发步骤

    1.QQ物联开发步骤 1)测试环境无需申请上线,即可任意调试.意思是什么呢,它是告诉大家,在调试的时候不要点击上面的提交上线,因为目还在调试此设备,一旦上线,QQ物联官方就会来审核你的设备,导致延长研 ...

  6. 字符的输入和输出即:getchar和putchar

    #include <stdio.h> int main(int argc, const char * argv[]) { putchar(getchar());//这种方式就是输入一个字符 ...

  7. php实现字符串替换

    php实现字符串替换 一.总结 二.php实现字符串替换 代码一: //字符串替换 function str_replace($substr , $newsubstr, $str) { $m = st ...

  8. struts2-token防止重复提交解决办法

    1.配置struts.xml全局防重复提交拦截器栈: <struts> <package name="module" extends="struts-d ...

  9. Android事件分发机制具体解释

    转载注明出处:http://blog.csdn.net/xiaohanluo/article/details/52416141 1. 概述 Android日常研发时,与View接触占领相当多的时间.而 ...

  10. html 页面 黑白

    css代码,写在最顶端 html {filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);-webkit-filter: ...