在 android 中创建文件时没有此类文件或目录异常(使用 f.createNewFile())

No such file or directory exception in creating a file in android(using f.createNewFile())

我正在尝试使用服务器套接字通过 android 发送图像文件。我在客户端使用了 AsyncTask class 并创建了一个 TransferFile class 来发送文件。在客户端创建文件时出现 NO SUCH FILE OR DIRECTORY 异常。代码附在下面。

权限。

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

传输文件class.

import android.app.IntentService;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

public class TransferFile extends IntentService{

private static final int SOCKET_TIMEOUT = 5000;
public static final String ACTION_SEND_FILE = "com.apposite.wifip2p.SEND_FILE";
public static final String EXTRAS_FILE_PATH = "file_url";
public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";

public TransferFile(){
    super("TransferFile");
}

@Override
protected void onHandleIntent(Intent intent) {
    Context context = getApplicationContext();
    Toast.makeText(this, "Client Socket Intent Handled.", Toast.LENGTH_SHORT).show();
    if (intent.getAction().equals(ACTION_SEND_FILE)) {
        Toast.makeText(context, "inside ACTION_SEND_FILE.", Toast.LENGTH_SHORT).show();
        String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
        String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
        Socket socket = new Socket();
        int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);

        try {
            socket.bind(null);
            socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);

            Toast.makeText(context, "Client Socket Connected: "+socket.isConnected(), Toast.LENGTH_SHORT).show();
            OutputStream stream = socket.getOutputStream();
            ContentResolver cr = context.getContentResolver();
            InputStream is = null;
            try {
                is = cr.openInputStream(Uri.parse(fileUri));
            }
            catch (FileNotFoundException e) {

            }
            MainActivity.copyFile(is, stream);
        } catch (IOException e) {
            Toast.makeText(context, "File can't be copied to client.", Toast.LENGTH_SHORT).show();
        } finally {
            if(socket.isConnected()){
                try {
                    socket.close();
                } catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}
}

主要活动class

import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements WifiP2pManager.PeerListListener, WifiP2pManager.ConnectionInfoListener{

    WifiP2pManager wifi;
    private WifiP2pInfo info;
    ListView listViewPeer;
    WifiP2pManager.Channel channel;
    IntentFilter intentFilter = new IntentFilter();
    Button discover, send;
    List<WifiP2pDevice> peersList;
    List<String> peersNameList;
    BroadcastReceiver receiver = null;
    ProgressDialog progressDialog = null;
    boolean isConnected = false;
    protected static final int CHOOSE_FILE_RESULT_CODE = 20;
    Intent serviceIntent;
    boolean isHost = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        listViewPeer = (ListView) findViewById(R.id.ListViewPeer);
        discover = (Button) findViewById(R.id.btnDiscover);
        send = (Button) findViewById(R.id.btnGallery);


        wifi = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        channel = wifi.initialize(this, getMainLooper(), null);
        receiver = new WifiP2pBroadcastReceiver(wifi, channel, this);

        peersList = new ArrayList<>();
        peersNameList = new ArrayList<>();

        discover.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (progressDialog != null && progressDialog.isShowing()) {
                    progressDialog.dismiss();
                }
                progressDialog = ProgressDialog.show(MainActivity.this, "Press back to cancel", "finding peers", false,
                        true, new DialogInterface.OnCancelListener() {

                            @Override
                            public void onCancel(DialogInterface dialog) {
                                if(peersList.size()==0)
                                    Toast.makeText(MainActivity.this, "Peer Not Found.", Toast.LENGTH_SHORT).show();
                            }
                        });

                Runnable progressRunnable = new Runnable() {
                    @Override
                    public void run() {
                        if (progressDialog != null && progressDialog.isShowing()) {
                            progressDialog.dismiss();
                        }
                    }
                };
                Handler pdCanceller = new Handler();
                pdCanceller.postDelayed(progressRunnable, 15000);

                wifi.discoverPeers(channel, new WifiP2pManager.ActionListener(){
                    @Override
                    public void onSuccess() {

                    }

                    @Override
                    public void onFailure(int reason) {
                        Toast.makeText(MainActivity.this, "Peer Discovery failed.", Toast.LENGTH_SHORT).show();
                        if (progressDialog != null && progressDialog.isShowing()) {
                            progressDialog.dismiss();
                        }
                    }
                });
            }
        });

        refreshList();

        listViewPeer.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if(!isConnected)
                    connect(position);
                else
                    disconnect();
            }
        });

        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                intent.setType("image/*");
                startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE);
            }
        });

        if(!isConnected)
            send.setVisibility(View.GONE);
        else
            send.setVisibility(View.VISIBLE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        //super.onActivityResult(requestCode, resultCode, data);
        Uri uri = data.getData();
        serviceIntent = new Intent(this, TransferFile.class);
        serviceIntent.setAction(TransferFile.ACTION_SEND_FILE);
        serviceIntent.putExtra(TransferFile.EXTRAS_FILE_PATH, uri.toString());
        serviceIntent.putExtra(TransferFile.EXTRAS_GROUP_OWNER_ADDRESS, info.groupOwnerAddress.getHostAddress());
        serviceIntent.putExtra(TransferFile.EXTRAS_GROUP_OWNER_PORT, 8988);


        this.startService(serviceIntent);
        Toast.makeText(this, "TransferFile should start.", Toast.LENGTH_SHORT).show();
    }

    public void connect(int position) {

        final WifiP2pDevice device = peersList.get(position);
        WifiP2pConfig config = new WifiP2pConfig();
        config.deviceAddress = device.deviceAddress;
        config.wps.setup = WpsInfo.PBC;

        wifi.connect(channel, config, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {

            }

            @Override
            public void onFailure(int reason) {
                Toast.makeText(MainActivity.this, "Connect failed. Retry.", Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void disconnect() {
        send.setVisibility(View.GONE);
        wifi.removeGroup(channel, new WifiP2pManager.ActionListener() {

            @Override
            public void onFailure(int reasonCode) {
                Toast.makeText(MainActivity.this, "Device disconnecting failed.", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSuccess() {

            }

        });
    }

    @Override
    public void onResume() {
        super.onResume();
        registerReceiver(receiver, intentFilter);
        send.setVisibility(View.GONE);
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
    }

    @Override
    protected void onDestroy() {
        super.onStop();
        if(isHost)
            stopService(serviceIntent);
    }

    @Override
    public void onPeersAvailable(WifiP2pDeviceList peers) {
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
        }

        peersList.clear();
        peersList.addAll(peers.getDeviceList());

        refreshList();
    }
    public void refreshList(){
        peersNameList.clear();
        if(peersList.size()!=0){
            for(int i=0;i<peersList.size();i++){
                peersNameList.add(i, peersList.get(i).deviceName);
            }
        }
        else
            send.setVisibility(View.GONE);
        final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, peersNameList);
        listViewPeer.setAdapter(arrayAdapter);
    }

    @Override
    public void onConnectionInfoAvailable(WifiP2pInfo info) {
        this.info = info;
        if(!isConnected){
            Toast.makeText(MainActivity.this, "Device Connected.", Toast.LENGTH_SHORT).show();
            isConnected = true;
            if (info.groupFormed && info.isGroupOwner) {
                isHost = false;
                new FileServerAsyncTask(this).execute();

            }
            else if(info.groupFormed)
                send.setVisibility(View.VISIBLE);
            else
                Toast.makeText(MainActivity.this, "Nothing matters", Toast.LENGTH_SHORT).show();
        }
    }

    public void reset(){
        if(isConnected){
            Toast.makeText(MainActivity.this, "Device Disconnected.", Toast.LENGTH_SHORT).show();
            isConnected = false;
            send.setVisibility(View.GONE);
        }
    }
    public class FileServerAsyncTask extends AsyncTask<Void, Void, String> {

        Context context;

        FileServerAsyncTask(Context context) {
            this.context = context;
        }

        @Override
        protected String doInBackground(Void... params) {
            try {
                ServerSocket serverSocket = new ServerSocket(8988);
                Socket client = serverSocket.accept();

                final File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/"
                        + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
                        + ".jpg");

                File dirs = new File(f.getParent());
                if (!dirs.exists())
                    dirs.mkdirs();

                // Here
                // is
                // the
                // ERROR
                f.createNewFile();

                InputStream inputstream = client.getInputStream();
                copyFile(inputstream, new FileOutputStream(f));
                serverSocket.close();
                return f.getAbsolutePath();
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }

        @Override
        protected void onPostExecute(String result) {
            Toast.makeText(context, "inside post execute." + result, Toast.LENGTH_SHORT).show();

            if (result != null) {
                Intent intent = new Intent();
                intent.setAction(android.content.Intent.ACTION_VIEW);
                intent.setDataAndType(Uri.parse("file://" + result), "image/*");
                context.startActivity(intent);
            }
        }
        @Override
        protected void onPreExecute() {
            Toast.makeText(context, "Opening a server socket", Toast.LENGTH_SHORT).show();
        }
    }
    public static boolean copyFile(InputStream inputStream, OutputStream out) {
        byte buf[] = new byte[1024];
        int len;

        try {
            while ((len = inputStream.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
            out.close();
            inputStream.close();


        } catch (IOException e) {
            return false;
        }
        return true;
    }
}

这是我的 FileServerAsycTask class

public class FileServerAsyncTask extends AsyncTask<Void, Void, String> {

            Context context;

            FileServerAsyncTask(Context context) {
                this.context = context;
            }

            @Override
            protected String doInBackground(Void... params) {
                try {
                    ServerSocket serverSocket = new ServerSocket(8988);
                    Socket client = serverSocket.accept();

                    final File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/"
                            + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
                            + ".jpg");

                    File dirs = new File(f.getParent());
                    if (!dirs.exists())
                        dirs.mkdirs();

                    // Here
                    // is
                    // the
                    // ERROR
                    f.createNewFile();

                    InputStream inputstream = client.getInputStream();
                    copyFile(inputstream, new FileOutputStream(f));
                    serverSocket.close();
                    return f.getAbsolutePath();
                } catch (IOException e) {
                    e.printStackTrace();
                    return null;
                }
            }

            @Override
            protected void onPostExecute(String result) {
                Toast.makeText(context, "inside post execute." + result, Toast.LENGTH_SHORT).show();

                if (result != null) {
                    Intent intent = new Intent();
                    intent.setAction(android.content.Intent.ACTION_VIEW);
                    intent.setDataAndType(Uri.parse("file://" + result), "image/*");
                    context.startActivity(intent);
                }
            }
            @Override
            protected void onPreExecute() {
                Toast.makeText(context, "Opening a server socket", Toast.LENGTH_SHORT).show();
            }
        }
        public static boolean copyFile(InputStream inputStream, OutputStream out) {
            byte buf[] = new byte[1024];
            int len;

            try {
                while ((len = inputStream.read(buf)) != -1) {
                    out.write(buf, 0, len);
                }
                out.close();
                inputStream.close();


            } catch (IOException e) {
                return false;
            }
            return true;
        }

在客户端,我尝试使用 f.createNewFile() 创建一个新文件,它给我一个错误 "No such file or directory"。

W/System.err: java.io.IOException: open failed: ENOENT (No such file or directory)
W/System.err:     at java.io.File.createNewFile(File.java:939)
W/System.err:     at com.apposite.wifip2p.MainActivity$FileServerAsyncTask.doInBackground(MainActivity.java:360)
W/System.err:     at com.apposite.wifip2p.MainActivity$FileServerAsyncTask.doInBackground(MainActivity.java:310)
W/System.err:     at android.os.AsyncTask.call(AsyncTask.java:295)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err:     at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:234)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
W/System.err:     at java.lang.Thread.run(Thread.java:818)
W/System.err: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
W/System.err:     at libcore.io.Posix.open(Native Method)
W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
W/System.err:     at java.io.File.createNewFile(File.java:932)
W/System.err:   ... 8 more

文件名是...

/storage/emulated/0/com.apposite.wifip2pwifip2pshared-1489935211585.jpg

请帮我解决一下!

创建 Intent 以将 Uri 传递给服务时:

  • 放入 Intent 的数据面(setData(),而不是 putExtra()),并且
  • Intent 上调用 addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),然后再调用 startService()

您的 activity 有权访问此内容;如果没有这些更改,您的服务将无法访问内容。

此外,如果您的 targetSdkVersion 为 23 或更高,并且您在 Android 6.0+ 上 运行,则需要 handle runtime permissions