0

在我的程序中,我使用了 JSch 包文档中一个示例的改编版本,该包描述了如何将文件从远程服务器复制到本地计算机。尽管该程序似乎可以运行,但文件似乎在复制过程中已损坏,当我尝试从 bash 播放它们时,我收到一条错误消息,显示为“播放失败格式:无法打开输入文件 `79_97_729.wav' :WAVE:未找到 RIFF 标头”。

我的复制方法如下:

public void copyFile(File file, String newName) throws JSchException, IOException{

    String prefix = null;
    if (new File(destination).isDirectory()){
        prefix = destination + File.separator;
    }

    JSch jsch = new JSch();
    Session session = jsch.getSession("username", "network");
    session.setUserInfo(new MyUserInfo());
    session.connect();

    String command = "scp -f " + file.getAbsolutePath();
    Channel channel = session.openChannel("exec");
    ((ChannelExec)channel).setCommand(command);

    OutputStream out = channel.getOutputStream();
    InputStream in = channel.getInputStream();

    channel.connect();

    byte[] buf = new byte[1024];

    // send '\0'
    buf[0]=0; out.write(buf, 0, 1); out.flush();

    while(true){
        int c=checkAck(in);
        if(c!='C'){
            break;
        }

        // read '0644 '
        in.read(buf, 0, 5);

        long filesize=0L;
        while(true){
            if(in.read(buf, 0, 1)<0){
                // error
                break;
            }
            if(buf[0]==' ')break;
            filesize=filesize*10L+(long)(buf[0]-'0');
        }

        // send '\0'
        buf[0]=0; out.write(buf, 0, 1); out.flush();

        // read a content of lfile
        fos=new FileOutputStream(prefix == null ? destination : prefix + newName);
        int foo;
        while(true){
            if(buf.length<filesize) foo=buf.length;
            else foo=(int)filesize;
            foo=in.read(buf, 0, foo);
            if(foo<0){
                // error
                break;
            }
            fos.write(buf, 0, foo);
            filesize-=foo;
            if(filesize==0L) break;
        }
        fos.close();
        fos=null;

        // send '\0'
        buf[0]=0; out.write(buf, 0, 1); out.flush();
    }

    session.disconnect();
}

我可以做一些调整来控制我正在复制的文件是 wav 格式的事实吗?任何帮助,将不胜感激!

4

1 回答 1

0

这就是我使用的:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.regex.Pattern;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class Scp {
    private static final Logger log = LoggerFactory.getLogger( Scp.class );
    private static final Pattern validMode = Pattern.compile( "^[0-8]{3,4}$" );
    private Session session;
    private String message;
    private String mode = "0664";
    private int bufferSize = 1024;

    public Scp( Session session ) {
        log.trace( "creating scp object" );
        this.session = session;
    }

    public String getMessage() {
        return message;
    }

    public String getMode() {
        return mode;
    }

    public int send( String localPath, String remotePath )
            throws JSchException, IOException {
        log.trace( "copying '{}' to '{}'", localPath, remotePath );
        int ack = 0;

        Channel channel = null;
        try {
            channel = session.openChannel( "exec" );
            ((ChannelExec) channel).setCommand( new StringBuilder( "scp -p -t " )
                    .append( remotePath ).toString() );
            OutputStream channelOut = channel.getOutputStream();
            InputStream channelIn = channel.getInputStream();

            channel.connect();

            if ( (ack = checkAck( channelIn )) != 0 ) return ack;

            File localFile = new File( localPath );
            channelOut.write( new StringBuilder( "C" )
                    .append( mode )
                    .append( " " )
                    .append( localFile.length() )
                    .append( " " )
                    .append( localFile.getName() )
                    .append( "\n" )
                    .toString().getBytes() );
            channelOut.flush();

            if ( (ack = checkAck( channelIn )) != 0 ) return ack;

            FileInputStream fileIn = new FileInputStream( localFile );
            try {
                byte[] buffer = new byte[bufferSize];
                int bytesRead;
                while ( (bytesRead = fileIn.read( buffer, 0, bufferSize )) >= 0 ) {
                    channelOut.write( buffer, 0, bytesRead );
                }

                // finish the stream by writing a null terminator
                buffer[0] = 0;
                channelOut.write( buffer, 0, 1 );
                channelOut.flush();
            }
            finally {
                if ( fileIn != null ) {
                    try {
                        fileIn.close();
                    }
                    catch ( Exception e ) {
                        log.warn( "failed to close filehandle: {}", e );
                    }
                }
                fileIn = null;
            }

            if ( (ack = checkAck( channelIn )) != 0 ) return ack;
        }
        finally {
            if ( channel != null && channel.isConnected() ) {
                channel.disconnect();
            }
        }

        message = "success";
        return ack;
    }

    private int checkAck( InputStream in ) throws IOException {
        int b = in.read();

        if ( b == 1 || b == 2 ) {
            StringBuilder builder = new StringBuilder();
            int c;
            while ( (c = in.read()) != '\n' ) {
                builder.append( (char) c );
            }
            message = builder.toString();
        }

        return b;
    }

    public void setBufferSize( int bufferSize ) {
        this.bufferSize = bufferSize;
    }

    /**
     * Sets the mode of the destination file. By default, it is 0664.
     * 
     * @param mode
     *            The mode to set the destination file to.
     */
    public void setMode( String mode ) {
        if ( !validMode.matcher( mode ).matches() ) {
            throw new IllegalArgumentException( "invalid mode, must be 3 or 4 octal numbers (/^[0-8]{3,4}$/)" );
        }
        this.mode = (mode.length() == 3) ? ("0" + mode) : mode;
    }
}

它可以可靠地传输所有类型的媒体。

- - - - - 编辑 - - - - -

这是一个单元测试,证明这适用于 wav 文件:

import static org.junit.Assert.assertTrue;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;


import javax.crypto.NoSuchPaddingException;


import org.junit.Test;
import org.mitre.asias.sch.Scp;


import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;


public class ScpTest {
    @Test
    public void testScpWav() throws JSchException, IOException, NoSuchAlgorithmException, NoSuchPaddingException {
        String dotSshDir = "C:/Cygwin/home/me/.ssh";
        JSch jsch = new JSch();
        jsch.setKnownHosts( dotSshDir + "/known_hosts" );
        jsch.addIdentity( dotSshDir + "/id_dsa" );

        Session session = jsch.getSession( "me", "localhost" );
        session.connect();

        Scp scp = new Scp( session );
        scp.send( "data/SpeechOn.wav", "/tmp/" );

        assertTrue( Arrays.equals( readFileFully( "data/SpeechOn.wav" ), readFileFully( "C:/Cygwin/tmp/SpeechOn.wav" ) ) );
    }

    public byte[] readFileFully( String fileName ) throws IOException {
        InputStream is = null;
        try {
            is = new FileInputStream( new File( fileName ) );
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();

            int nRead;
            byte[] data = new byte[16384];

            while ( (nRead = is.read( data, 0, data.length )) != -1 ) {
                buffer.write( data, 0, nRead );
            }

            buffer.flush();

            return buffer.toByteArray();
        }
        finally {
            if ( is != null ) {
                is.close();
            }
        }

    }
}

您应该能够在修改源/目标文件的位置时对这个单元测试进行修改,dotSshDir并且它应该可以工作。它对我有用。

于 2012-07-26T21:03:23.947 回答