Android設(shè)備與外接U盤實現(xiàn)數(shù)據(jù)讀取操作的示例
現(xiàn)在越來越多手機支持OTG功能,通過OTG可以實現(xiàn)與外接入的U盤等USB設(shè)備實現(xiàn)數(shù)據(jù)傳輸。
USB OTG(On The Go)作為USB2.0的補充協(xié)議,于2001年由USB-IF提出。它提出的背景是移動消費類電子產(chǎn)品的迅猛增加,而之前USB協(xié)議的主從協(xié)議標準讓這些電子產(chǎn)品在離開PC電腦時的數(shù)據(jù)傳輸變得艱難,OTG技術(shù)正是為了解決這一問題的標準。
通過OTG技術(shù)實現(xiàn)設(shè)備間端到端互聯(lián)
OTG協(xié)議規(guī)定連接時默認情況作為Host的設(shè)備為A設(shè)備,A設(shè)備負責為總線供電;默認作為Device的設(shè)備為B設(shè)備(USB OTG標準在完全兼容USB2.0標準的基礎(chǔ)上,增加了一個ID pin;ID拉低為默認A設(shè)備);而有些設(shè)備由于集成了Host控制器和Device控制器,既可以作A設(shè)備又可以做B設(shè)備,稱為dura-role device。
最近項目上用到了該功能,項目上用的是安卓7.1的盒子,要實現(xiàn)與插入的U盤進行數(shù)據(jù)操作。通過大量的找資料,終于實現(xiàn)了項目上需要的功能。找資料主要是解決兩個問題:
- U盤權(quán)限問題
- U盤文件路徑及文件操作
廢話不多說,感覺還是喜歡直接上代碼才爽快。項目中用到了一個開源框架,開源地址是:
https://github.com/magnusja/libaums。
代碼部分:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { //輸入的內(nèi)容 private EditText u_disk_edt; //寫入到U盤 private Button u_disk_write; //從U盤讀取 private Button u_disk_read; //顯示讀取的內(nèi)容 private TextView u_disk_show; //自定義U盤讀寫權(quán)限 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 100: showToastMsg("保存成功"); break; case 101: String txt = msg.obj.toString(); if (!TextUtils.isEmpty(txt)) u_disk_show.setText("讀取到的數(shù)據(jù)是:" + 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[0]; try { usbFiles = cFolder.listFiles(); } catch (IOException e) { e.printStackTrace(); } if (null != usbFiles && usbFiles.length > 0) { for (UsbFile usbFile : usbFiles) { if (usbFile.getName().equals(U_DISK_FILE_NAME)) { readTxtFromUDisk(usbFile); } } } } /** * @description 保存數(shù)據(jù)到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(100); } } /** * @description OTG廣播注冊 * @author ldm * @time 2017/9/1 17:19 */ private void registerUDiskReceiver() { //監(jiān)聽otg插入 拔出 IntentFilter usbDeviceStateFilter = new IntentFilter(); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); registerReceiver(mOtgReceiver, usbDeviceStateFilter); //注冊監(jiān)聽自定義廣播 IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(mOtgReceiver, filter); } /** * @description OTG廣播,監(jiān)聽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); //允許權(quán)限申請 if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if (usbDevice != null) { //用戶已授權(quán),可以進行讀取操作 readDevice(getUsbMass(usbDevice)); } else { showToastMsg("沒有插入U盤"); } } else { showToastMsg("未獲取到U盤權(quán)限"); } break; case UsbManager.ACTION_USB_DEVICE_ATTACHED://接收到U盤設(shè)備插入廣播 UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device_add != null) { //接收到U盤插入廣播,嘗試讀取U盤設(shè)備數(shù)據(jù) redUDiskDevsList(); } break; case UsbManager.ACTION_USB_DEVICE_DETACHED://接收到U盤設(shè)設(shè)備拔出廣播 showToastMsg("U盤已拔出"); break; } } }; /** * @description U盤設(shè)備讀取 * @author ldm * @time 2017/9/1 17:20 */ private void redUDiskDevsList() { //設(shè)備管理器 UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); //獲取U盤存儲設(shè)備 storageDevices = UsbMassStorageDevice.getMassStorageDevices(this); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); //一般手機只有1個OTG插口 for (UsbMassStorageDevice device : storageDevices) { //讀取設(shè)備是否有權(quán)限 if (usbManager.hasPermission(device.getUsbDevice())) { readDevice(device); } else { //沒有權(quán)限,進行申請 usbManager.requestPermission(device.getUsbDevice(), pendingIntent); } } if (storageDevices.length == 0) { 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();//初始化 //設(shè)備分區(qū) Partition partition = device.getPartitions().get(0); //文件系統(tǒng) FileSystem currentFs = partition.getFileSystem(); currentFs.getVolumeLabel();//可以獲取到設(shè)備的標識 //通過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();//設(shè)置當前文件對象為根目錄 } 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; //讀取文件內(nèi)容 InputStream is = new UsbFileInputStream(descFile); //讀取秘鑰中的數(shù)據(jù)進行匹配 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 = 101; msg.obj = read; mHandler.sendMessage(msg); } catch (Exception e) { e.printStackTrace(); } finally { try { if (bufferedReader != null) { bufferedReader.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
對應(yīng)布局文件:
<?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盤中的文字內(nèi)容"/> <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盤中寫入數(shù)據(jù)"/> <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盤中讀取數(shù)據(jù)"/> <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 如果文件不存在則創(chuàng)建, 如果如果無法創(chuàng)建文件或文件名為空則返回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卡下的指定文件夾對象,若文件夾不存在則創(chuàng)建 */ public static File getSaveFolder(String folderName) { File file = new File(getExternalStorageDirectory() .getAbsoluteFile() + File.separator + folderName + File.separator); file.mkdirs(); return file; } /** * 關(guān)閉流 */ public static void closeIO(Closeable... closeables) { if (null == closeables || closeables.length <= 0) { 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 = 0; byte[] buffer = new byte[1024 * 8]; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, 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 > 0) { 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中添加權(quán)限:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
時間關(guān)系,就不貼圖了,歡迎指導(dǎo)交流。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android開發(fā)實現(xiàn)的電話竊聽和攔截應(yīng)用
這篇文章主要介紹了Android開發(fā)實現(xiàn)的電話竊聽和攔截應(yīng)用,結(jié)合實例形式分析了Android針對電話的監(jiān)聽與攔截的相關(guān)技巧,需要的朋友可以參考下2016-08-08Android 判斷SIM卡屬于哪個移動運營商的實現(xiàn)代碼
有時候我們需要在Android中獲取本機網(wǎng)絡(luò)提供商呢,這里簡單分享下,方便需要的朋友2013-05-05Android自定義ViewGroup實現(xiàn)右滑進入詳情
這篇文章主要為大家詳細介紹了Android如何通過自定義ViewGroup實現(xiàn)右滑進入詳情效果,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-01-01Android如何獲取系統(tǒng)通知的開啟狀態(tài)詳解
這篇文章主要給大家介紹了關(guān)于Android如何獲取系統(tǒng)通知開啟狀態(tài)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對各位Android開發(fā)者們具有一定的參考學習價值,需要的朋友們下面跟著小編來一起看看吧啊。2017-08-08Android 使用Vitamio打造自己的萬能播放器(3)——本地播放(主界面、播放列表)
本文主要介紹 Android Vitamio本地播放功能,這里提供實例代碼和效果圖以便大家參考,有需要的小伙伴可以參考下2016-07-07Android中利用NetworkInfo判斷網(wǎng)絡(luò)狀態(tài)時出現(xiàn)空指針(NullPointerException)問題的解決
這篇文章主要介紹了Android中利用NetworkInfo判斷網(wǎng)絡(luò)狀態(tài)時出現(xiàn)空指針(NullPointerException)問題的解決方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-11-11