2015-07-12 76 views
2

我目前正在开发一个应用程序,该应用程序可以打印远程服务器目录中的文件列表,并且可以单击指定的文件并下载它。使用onClick从远程服务器下载SFTP

到目前为止,这是我:

public class MainActivity extends Activity { 


    private String user = "username"; 
    private String pass = "password"; 
    private String host = "hostname"; 
    private int portNum = 22; 

    private static final String SFTPWORKINGDIR = "/path/to/file"; 
    private String fileName; 

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

     final ListView list = (ListView)findViewById(R.id.choose_sound_listView); 

     new AsyncTask<Void, Void, List<String>>() { 
      @Override 
      protected List<String> doInBackground(Void... params) { 
       try { 
        return executeRemoteCommand(user, pass, host, portNum); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
       return null; 
      } 

      @Override 
      public void onPostExecute(List<String> soundNames){ 
       ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_expandable_list_item_1, android.R.id.text1, soundNames); 
       list.setAdapter(adapter); 

       list.setOnItemClickListener(new AdapterView.OnItemClickListener() { 

        @Override 
        public void onItemClick(AdapterView<?> arg0, View arg1, 
              int position, long arg3) { 

         String newFileName = (String) list.getItemAtPosition(position); 

         fileName = newFileName; 

         Downloader(fileName); 

         // Show Alert 
         Toast.makeText(getApplicationContext(), 
           "Downloaded " + fileName , Toast.LENGTH_LONG).show(); 
        } 
       }); 
      } 
     }.execute(); 
    } 

    public List<String> executeRemoteCommand(String username, String password, String hostname, int port) throws Exception { 

     List<String> soundNames = new ArrayList<String>(); 

     JSch jsch = new JSch(); 
     Session session = jsch.getSession(username, hostname, port); 
     session.setPassword(password); 

     // Avoid asking for key confirmation 
     Properties prop = new Properties(); 
     prop.put("StrictHostKeyChecking", "no"); 
     session.setConfig(prop); 

     session.connect(); 

     String command = "ls -la | awk '{ print $9}'"; 

     Channel channel = session.openChannel("exec"); 
     ((ChannelExec) channel).setCommand(command); 

     ((ChannelExec) channel).setErrStream(System.err); 

     InputStream in = channel.getInputStream(); 

     System.out.println("Connect to session..."); 
     channel.connect(); 

     StringBuffer buffer = new StringBuffer(); 

     //This is the recommended way to read the output 
     byte[] tmp = new byte[1024]; 
     while (true) { 
      while (in.available() > 0) { 
       int i = in.read(tmp, 0, 1024); 
       if (i < 0) { 
        break; 
       } 
       buffer.append(new String(tmp, 0, i)); 
      } 
      if (channel.isClosed()) { 
       System.out.println("exit-status: " + channel.getExitStatus()); 
       break; 
      } 
      try { 
       Thread.sleep(1000); 
      } catch (Exception ee) { 
      } 
     } 

     channel.disconnect(); 
     session.disconnect(); 

     Scanner scanner = new Scanner(buffer.toString()); 
     while (scanner.hasNextLine()){ 
      String line = scanner.nextLine(); 
      soundNames.add(line); 

      Log.i("SSH", ": " + line); 
     } 

     return soundNames; 
    } 


    public void Downloader(String fileName) { 

     JSch jsch = new JSch(); 
     Session session = null; 
     Channel channel = null; 
     ChannelSftp sftpChannel = null; 

     try { 

      session = jsch.getSession(user, host, portNum); 
      session.setConfig("StrictHostKeyChecking", "no"); 
      session.setPassword(pass); 
      session.connect(); 

      channel = session.openChannel("sftp"); 
      channel.connect(); 
      sftpChannel = (ChannelSftp) channel; 
      sftpChannel.cd(SFTPWORKINGDIR); //cd to dir that contains file 

      try { 
       byte[] buffer = new byte[1024]; 
       BufferedInputStream bis = new BufferedInputStream(sftpChannel.get(fileName)); 

       File path = Environment.getExternalStoragePublicDirectory(
         Environment.DIRECTORY_DOCUMENTS); 
       File newFile = new File(path, "/" + fileName); 

       Log.d("Dir" , " " + newFile); 

       OutputStream os = new FileOutputStream(newFile); 
       BufferedOutputStream bos = new BufferedOutputStream(os); 
       int readCount; 
       while((readCount = bis.read(buffer)) > 0) { 
        Log.d("Downloading", " " + fileName); 
        bos.write(buffer, 0, readCount); 
       } 
       bis.close(); 
       bos.close(); 

      } catch (FileNotFoundException e) { 
       e.printStackTrace(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

      Log.d("SUCCESS ", fileName + " has been downloaded!!!!"); 

      sftpChannel.exit(); 
      session.disconnect(); 

     } catch (JSchException e) { 
      e.printStackTrace(); 
     } catch (SftpException e) { 
      e.printStackTrace(); 
     } 
    } 


    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.menu_main, menu); 
     return true; 
    } 
} 

但是,当我点击在ListView的文件,我得到一丝错误:

com.jcraft.jsch。 JSchException:android.os.NetworkOnMainThreadException

编辑:上运行它背景的AsyncTask似乎修复错误,但如果我这样做,除非硬编码文件的名称,否则该应用程序将无法下载指定的onClick文件。

任何人都知道我可以解决这个问题吗?

+1

可能重复的线程中运行,你应该将任何网络到doInBackground。 NetworkOnMainThreadException](http://stackoverflow.com/questions/6343166/android-os-networkonmainthreadexception) –

回答

0

您在onPostExecute(List<String> soundNames)执行Downloader(String fileName)。但在主线程上执行。只有doInBackground()在单独的线程上执行。将执行Downloader(String fileName)移至doInBackground()

编辑:或创建一个单独的AsyncTask,它在自己的doInBackground()

+0

我能够解决这个错误,在onPostExecute内制作一个新的AsyncTask。谢谢! – adventuredoge

0

您正在主应用程序线程上执行网络I/O,如异常所示。如果您查看堆栈跟踪,它会指出您在主应用程序线程上执行网络I/O的确切位置。

最有可能来自Downloader()方法,因为您确实正在使用该方法中的网络I/O,并且该方法从onItemClick()调用,该方法本身在主应用程序线程中调用。请在后台线程上执行此下载。

0

执行Downloader(String fileName)使其[android.os的的AsyncTask

相关问题