Android U盤讀寫要用到的三方庫:https://github.com/magnusja/libaums,使用方法地那就連結了解。
最近項目需要用到OTG功能,寫了一個小demo,做為自己的筆記也供大家參考。
需要用到的權限:
USB插拔廣播
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.util.Log; import com.example.usbreadwriterdaemon.MainActivity; import com.example.usbreadwriterdaemon.utils.ToastUtil; import org.greenrobot.eventbus.EventBus; /** * Created by sws on 2018/8/28 * <p> * USB插拔廣播 */ public class UsbStateChangeReceiver extends BroadcastReceiver { private static final String TAG = "UsbStateChangeReceiver"; private boolean isConnected; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) { isConnected = true; ToastUtil.showToast("onReceive: USB裝置已連接配接"); UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device_add != null) { EventBus.getDefault().post(new UsbStatusChangeEvent(isConnected)); } else { ToastUtil.showToast("onReceive: device is null"); } } else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) { //Log.i(TAG, "onReceive: USB裝置已分離"); isConnected = false; ToastUtil.showToast("onReceive: USB裝置已拔出"); EventBus.getDefault().post(new UsbStatusChangeEvent(isConnected)); } else if (action.equals(MainActivity.ACTION_USB_PERMISSION)) { UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); //允許權限申請 if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if (usbDevice != null) { Log.i(TAG, "onReceive: 權限已擷取"); EventBus.getDefault().post(new UsbStatusChangeEvent(true, usbDevice)); } else { ToastUtil.showToast("沒有插入U盤"); } } else { ToastUtil.showToast("未擷取到U盤權限"); } } else { //Log.i(TAG, "onReceive: action=" + action); ToastUtil.showToast("action= " + action); } } }
USB狀态類,結合EventBus使用
import android.hardware.usb.UsbDevice; /** * Created by swson 2018/8/28 * <p> * Description:TODO */ public class UsbStatusChangeEvent { public boolean isConnected = false; public boolean isGetPermission = false; public UsbDevice usbDevice; public String filePath = ""; public UsbStatusChangeEvent(boolean isConnected) { this.isConnected = isConnected; } public UsbStatusChangeEvent(String filePath) { this.filePath = filePath; } public UsbStatusChangeEvent(boolean isGetPermission, UsbDevice usbDevice) { this.isGetPermission = isGetPermission; this.usbDevice = usbDevice; } }
app gradle添加依賴:
implementation 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' implementation 'org.greenrobot:eventbus:3.0.0' implementation 'com.github.mjdev:libaums:0.5.5'
檔案操作工具類FileUtil:
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; /** * Created by sws on 2018/8/28 * 檔案操作工具類 * Description:TODO */ 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 <= 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(); } } }
首頁--U盤的讀取寫入
import android.annotation.SuppressLint; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.example.usbreadwriterdaemon.receiver.UsbStateChangeReceiver; import com.example.usbreadwriterdaemon.receiver.UsbStatusChangeEvent; import com.example.usbreadwriterdaemon.utils.FileUtil; import com.example.usbreadwriterdaemon.utils.ToastUtil; import com.github.mjdev.libaums.UsbMassStorageDevice; import com.github.mjdev.libaums.fs.FileSystem; import com.github.mjdev.libaums.fs.UsbFile; import com.github.mjdev.libaums.fs.UsbFileInputStream; import com.github.mjdev.libaums.partition.Partition; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @BindView(R.id.u_disk_edt) EditText mUDiskEdt; @BindView(R.id.u_disk_write) Button mUDiskWrite; @BindView(R.id.u_disk_read) Button mUDiskRead; @BindView(R.id.u_disk_show) TextView mUDiskShow; private UsbMassStorageDevice[] storageDevices; private UsbFile cFolder; //自定義U盤讀寫權限 public static final String ACTION_USB_PERMISSION = "com.example.usbreadwriterdaemon.USB_PERMISSION"; private final static String U_DISK_FILE_NAME = "taiyuan.doc"; @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 100: ToastUtil.showToast("儲存成功"); break; case 101: String txt = msg.obj.toString(); if (!TextUtils.isEmpty(txt)) mUDiskShow.setText("讀取到的資料是:" + txt); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_method_one); ButterKnife.bind(this); EventBus.getDefault().register(this); registerUDiskReceiver(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onNetworkChangeEvent(UsbStatusChangeEvent event) { if (event.isConnected) { //接收到U盤插入廣播,嘗試讀取U盤裝置資料 redUDiskDevsList(); } else if (event.isGetPermission) { UsbDevice usbDevice = event.usbDevice; //使用者已授權,可以進行讀取操作 Log.i(TAG, "onNetworkChangeEvent: "); ToastUtil.showToast("onReceive: 權限已擷取"); readDevice(getUsbMass(usbDevice)); } else { } } @OnClick({R.id.u_disk_write, R.id.u_disk_read}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.u_disk_write: final String content = mUDiskEdt.getText().toString().trim(); mHandler.post(new Runnable() { @Override public void run() { saveText2UDisk(content); } }); break; case R.id.u_disk_read: readFromUDisk(); break; } } /** * @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(100); } } StringBuffer stringBuffer = new StringBuffer(); 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) { stringBuffer.append(", " + usbFile.getName()); if (usbFile.getName().equals(U_DISK_FILE_NAME)) { readTxtFromUDisk(usbFile); } } //mUDiskShow.setText("檔案名:" + stringBuffer.toString()); } } /** * @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, 0, new Intent(ACTION_USB_PERMISSION), 0); //一般手機隻有1個OTG插口 for (UsbMassStorageDevice device : storageDevices) { //讀取裝置是否有權限 if (usbManager.hasPermission(device.getUsbDevice())) { ToastUtil.showToast("有權限"); readDevice(device); } else { ToastUtil.showToast("沒有權限,進行申請"); //沒有權限,進行申請 usbManager.requestPermission(device.getUsbDevice(), pendingIntent); } } if (storageDevices.length == 0) { ToastUtil.showToast("請插入可用的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(0); //檔案系統 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() + ""); ToastUtil.showToast("可用空間:" + currentFs.getFreeSpace()); cFolder = currentFs.getRootDirectory();//設定目前檔案對象為根目錄 } catch (Exception e) { e.printStackTrace(); } } private void readTxtFromUDisk(UsbFile usbFile) { Log.i(TAG, "readTxtFromUDisk: "); 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 = 101; msg.obj = sb; mHandler.sendMessage(msg); } catch (Exception e) { e.printStackTrace(); } finally { try { if (bufferedReader != null) { bufferedReader.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** * usb插拔廣播 注冊 */ private void registerUDiskReceiver() { IntentFilter usbDeviceStateFilter = new IntentFilter(); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); usbDeviceStateFilter.addAction("android.hardware.usb.action.USB_STATE"); usbDeviceStateFilter.addAction(ACTION_USB_PERMISSION); //自定義廣播 registerReceiver(new UsbStateChangeReceiver(), usbDeviceStateFilter); } @Override protected void onDestroy() { super.onDestroy(); if (EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().unregister(this); } } }