• 用Java开发局域网内文件传输软件遇到的一些问题


    项目地址:https://github.com/b84955189/FileTransfer

    由于巨懒的我不太喜欢使用U盘操作文件,特此开发一个简易的文件传输程序。
    目前仅限局域网内传输,后期会尝试写下跨网传输。
    本软件主要功能模块如下:
    (1) 文件收发模块

    (2) 局域网同网段用户检测模块

    (3) 用户配置模块
    文件收发模块:任意文件类型传输,仅限单个文件传输,可打包传输。
    局域网同网段用户检测模块:同网段用户广播,直接发送,无需目标IP,前提需要同一网段下,且没有限制广播发送。
    用户配置模块:用户自主选择是否允许同网段用户发现,自主选择文件保存目录,配置文件通过软件根目录下Config.cnf保存。


    1.由于发送的模块需要read接收模块的确认接受信息,所以需要一定的阻塞时间,设置为无限

    在这里插入图片描述
    注意:设置了无限超时后,也要注意连接时的超时,防止输入错误IP后,一直尝试连接。
    即可以单独设置连接超时:socket.connect(address,timeout);
    项目中示例(SendThread中):

     //0-为无限等待
     socket.setSoTimeout(0);
    //TCP连接--设置了连接超时
    socket.connect(address,3000);
    

    2. 局域网IP获取问题

    Java已经提供好了网络接口类,非常方便。

    详情见博文:https://blog.csdn.net/weixin_43670802/article/details/103166435

    3. 线程重复开启关闭问题

    项目中涉及暴露线程关闭于重启问题。

    由于同一线程对象的重启很麻烦,所以我省去了关闭过程,只是让其一直continue;wait()似乎也可以,可以尝试下)
    也就是说此线程一直没关过。

    //JVM默认初始化为false
    private boolean sign;
    /*
    线程无法重启!!!所以这辈子我也不把它给关了!!
     */
            while(true){
                if(sign) {
                    //重新获取广播地址
                    broadcastAddress = CommonUtils.getBroadcastAddress();
                    //重新打包
                    DatagramPacket packet = new DatagramPacket(data, 0, data.length, broadcastAddress, R.Configs.UDP_PORT);
                    System.out.println(packet.getAddress().getHostAddress());
                    socket.send(packet);
    
                    //1s一次
                    Thread.sleep(1000);
                }else{
                    //1s一次
                    Thread.sleep(1000);
                    continue;
                }
    
            }
            } catch(Exception e){
                e.printStackTrace();
                JOptionPane.showMessageDialog(null,R.Strings.NETWORK_CHANGE);
                //重新获取广播地址
                broadcastAddress=CommonUtils.getBroadcastAddress();
                //--test
                System.out.println(broadcastAddress.getHostAddress());
                //--test
                if(broadcastAddress!=null)
                this.run();
                else {
                    JOptionPane.showConfirmDialog(null,R.Strings.NOT_NETWORK);
                    System.exit(0);
                }
            }
        }
        /*
        线程开关
         */
        public void setSwitch(boolean sign){
            this.sign=sign;
    
        }
    

    补充:https://blog.csdn.net/taoszu/article/details/82728405

    4. 重复上传文件重名问题

    获取到发送模块的文件名之后,使用File类的exist()方法检测是否已经存在。然后再利用字符串处理函数改名。

    //输出文件路径+文件名
                thisFile=new File(fileDirectory,fileName);
                int fileCount=0;
                //判断文件名是否冲突
                while(thisFile.exists()){
                    int position=fileName.lastIndexOf(".");
                    String preFileName=fileName.substring(0,position);
                    String latFileType=fileName.substring(position);//不用去除'.'了
                    fileName=preFileName+"("+(++fileCount)+")"+latFileType;
                    thisFile=new File(fileDirectory,fileName);
    
                }
    

    另外,用户中止上传后(即接收模块会抛出异常),可以调用thisFile.delete();来删除无用文件。

    项目异常处理代码块中:

     //删除失败文件
                thisFile.delete();
    

    5. Java设置背景图片问题(复用)

    项目中将设置界面背景的函数写入了CommonUtils工具类,另外注意中间媒介(图床)JLabel的地址一直没有变。
    JLabel为MainView成员变量。(虽然很鸡肋。。。)

      /*
        设置JFrame背景
        前提-需要内容面板透明
    ````框架-载体地址-图片
         */
        public static void setBackground(JFrame jFrame,JLabel jLabel,Image image){
    
    
            JLayeredPane jLayeredPane=jFrame.getLayeredPane();
            jLayeredPane.remove(jLabel);
            jLabel.setIcon(new ImageIcon(image));
            jLabel.setBounds(0,0,jFrame.getWidth(),jFrame.getHeight());
            jLayeredPane.add(jLabel,new Integer(Integer.MIN_VALUE));
    
            //jLayeredPane.add(jFrame.getContentPane(),new Integer(Integer.MAX_VALUE));
            //jFrame.remove(jFrame.getLayeredPane());
            //jFrame.setLayeredPane(jLayeredPane);
    
            jFrame.validate();
            jFrame.repaint();
    
    
        }
    

    7. 顶部图标问题

    本项目为了美化,即将初始标题栏去掉后,将图标放置在了JMenuBar上,自己体会吧。

     menuBar.add(Box.createHorizontalStrut(400));//间隔
    
            menuBar.add(minimizeMenuItem);
            menuBar.add(closeMenuItem);
    

    8.配置文件临时存储与写入问题

    本项目创建了一个配置信息类,程序全局配置信息全部从此类中(静态方法)获取。

    package transfer.data;
    
    public class Configs {
        //暴露开关,默认为开
        private static int udpSwitch=0;
        //默认保存地址为当前目录
        private static String fileDirectory=".";
    
        public static int getUdpSwitch() {
            return udpSwitch;
        }
    
        public static void setUdpSwitch(int udpSwitch) {
            Configs.udpSwitch = udpSwitch;
        }
    
        public static String getFileDiretory() {
            return fileDirectory;
        }
    
        public static void setFileDirectory(String fileDirectory) {
            Configs.fileDirectory = fileDirectory;
        }
        public static String toFile(){
            return udpSwitch+","+fileDirectory;
        }
        public static void fromFile(String config){
            String[] data=config.split(",");
            Configs.setUdpSwitch(Integer.parseInt(data[0]));
            Configs.setFileDirectory(data[1]);
        }
    }
    
    

    正常关闭时写入本机文件Config,cnf

     /*
        ---之所以不直接用字符流,是因为不想让人随意查看配置文件--抬高一点逼格,然并卵...haha...
         */
        private void saveConfigs(){
            DataOutputStream dataOutputStream=null;
            try {
                dataOutputStream = new DataOutputStream(new FileOutputStream(configFile));
                dataOutputStream.writeUTF(Configs.toFile());
                dataOutputStream.close();
    
            }catch (Exception e){
                e.printStackTrace();
    
    
                try {
                    if (dataOutputStream!=null)
                        dataOutputStream.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
    
            }
        }
    

    打开时读取文件至Config类中的静态变量中:

      /*
        初始化读取配置文件
         */
        private void initConfig(){
            DataInputStream dataInputStream=null;
            try{
                dataInputStream=new DataInputStream(new FileInputStream(configFile));
                String config=dataInputStream.readUTF();
                if(config==null||config.equals(""))
                        throw new Exception();
                else{
                    Configs.fromFile(config);
                }
            }catch(Exception e){
                e.printStackTrace();
                JOptionPane.showMessageDialog(null,R.Strings.READ_CONFIG_ERROR,R.Strings.TIP_TITLE,JOptionPane.ERROR_MESSAGE);
    
    
            }
        }
    
  • 相关阅读:
    构建git+gerrit+repo的Android代码服务器
    简单学习:repo入门
    git checkout 命令详解
    python学习第一天
    window下的git工具msysgit的使用
    git基本操作
    echarts 使用示例
    管道命令
    jquery修改文档结构
    JavaScript正则表达式
  • 原文地址:https://www.cnblogs.com/tfxz/p/12621594.html
Copyright © 2020-2023  润新知