现在越来越多手机支持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. C#使用wkhtmltopdf.exe,HTML页面转化为PDF文档

    此文用来记录使用wkhtmltopdf.exe在C#代码中将html转换为PDF的过程: 1,在http://wkhtmltopdf.org/downloads.html 下载wkhtmltopdf. ...

  2. stm32单片机时钟中断的配置

    原作者:http://www.eeworld.com.cn/mcu/article_2016082828940.html 配置流程:   1:系统时钟初始化,包括系统时钟和要开放的IO口或者功能的时钟 ...

  3. tensorflow 的 Batch Normalization 实现(tf.nn.moments、tf.nn.batch_normalization)

    tensorflow 在实现 Batch Normalization(各个网络层输出的归一化)时,主要用到以下两个 api: tf.nn.moments(x, axes, name=None, kee ...

  4. 24、vb2_buffer和videobuf_buffer比较分析

    看韦东山视频第三期摄像头驱动中构造了自己的vivi驱动,但是使用的videoBuf结构体,新的版本用的是vb2_buffer结构,我机器上(ubuntu12.04)使用的内核是linux3.2,看了看 ...

  5. 前端css常用的选择小汇

    要使用css对HTML页面中的元素实现一对一,一对多或者多对一的控制,这就需要用到CSS选择器.选择器就是选择器用来指定样式的作用范围. 类选择器: 类选择器在css中比较常见,首先要在普通标签中设置 ...

  6. 初步安装git使用命令配置电脑中的git关联的账户

    原文地址 https://www.jianshu.com/p/39684a3ad4fa 出现问题 当我们初步使用git的时候,会报一些出乎预料的错误,比如:报错:fatal: unable to au ...

  7. Visual Stdio 环境下使用 GSL (GNU Scientific Library)

    Visual Stdio 环境下使用 GSL (GNU Scientific Library) 经測试.这里的方法不适用于VS2015. * 这篇文章有点过时了.建议从以下网址下载能够在 vs 环境下 ...

  8. [TypeScript] Find the repeated item in an array using TypeScript

    Say you have an array that has at least one item repeated. How would you find the repeated item. Thi ...

  9. 设计模式-适配器模式(Go语言描写叙述)

    在上一篇博客设计模式-策略模式(Go语言描写叙述)中我们用最简单的代码用go语言描写叙述了设计模式中的策略模式,用最简单的实例来描写叙述相信能够让刚開始学习的人能够非常轻松的掌握各种设计模式.继上篇博 ...

  10. word-vba-microsoft(中英文)

    中文 https://msdn.microsoft.com/zh-cn/vba/word-vba/articles/view-displaypageboundaries-property-word 英 ...