天天看點

Android OTG U盤檔案讀寫

Android U盤讀寫要用到的三方庫:https://github.com/magnusja/libaums,使用方法地那就連結了解。

最近項目需要用到OTG功能,寫了一個小demo,做為自己的筆記也供大家參考。

需要用到的權限:

Android OTG U盤檔案讀寫
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);
        }


    }
}