1

オープンソース ソフトウェア Motion に接続する Android アプリケーションを実装しようとしています。目標は、アプリケーションのステータスを確認し、最後にキャプチャされた画像を取得できるようにすることです。

私は Java でプログラミングすることはあまりありません。私のバックグラウンドは主に C と Python です。Android の UI 部分を理解する上で実際に問題が発生したことはありませんが、あらゆる種類のバイト バッファを操作するのは非常に苦痛であることがわかりました。Motion ソフトウェアには、非常に単純な HTTP API があります。Java では、URL 接続を開くのは簡単です。デフォルト ページからの応答は次のようになります。

Motion 3.2.12 Running [4] Threads
0
1
2
3

私の目的のために、アプリケーションが最初に実行する必要があるのは、スレッドの数を解析することです。ある時点で、最初の行からバージョン番号を取得することもできますが、現時点ではそれほど重要ではありません。

これが私のコードです

package com.hydrogen18.motionsurveillanceviewer;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import java.util.List;

public class MotionHttpApi {
    String host;
    int port = 80;
    boolean secure = false;

    int numberOfThreads = -1;

    String getBaseUrl()
    {
        StringBuilder sb = new StringBuilder();

        sb.append(secure ? "https://" : "http://");
        sb.append(host);
        sb.append(':');
        sb.append(port);

        return sb.toString();
    }

    public int getNumberOfCameras() throws IOException
    {
        if(numberOfThreads == -1)
        {
            retrieveSplash();
        }

        if(numberOfThreads == 1)
        {
            return 1;
        }
        return numberOfThreads - 1;
    }
    void retrieveSplash () throws IOException
    {
        URL url = new URL(getBaseUrl());

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();

        if(conn.getResponseCode()!=HttpURLConnection.HTTP_OK)
        {
            throw new IOException("Got response code" + conn.getResponseCode());
        }

        try{
            Byte[] buffer = new Byte[512];
            byte[] sbuf = new byte[128];
            int offset = 0;
            InputStream in = new BufferedInputStream(conn.getInputStream());

            boolean foundInfoString= false;
            while( ! foundInfoString)
            {
                //Check to make sure we have not run out of space
                if(offset == buffer.length)
                {
                    throw new IOException("Response too large");
                }

                //Read into the smaller buffer since InputStream
                //can't write to a Byte[]
                final int result = in.read(sbuf,0,sbuf.length);

                //Copy the data into the larger buffer
                for(int i = 0; i < result;++i)
                {
                    buffer[offset+i] = sbuf[i];
                }
                //Add to the offset
                offset+=result;

                //Wrap the array as a list
                List<Byte> list = java.util.Arrays.asList(buffer);  

                //Find newline character
                final int index = list.indexOf((byte) '\n');

                //If the newline is present, extract the number of threads
                if (index != -1)
                {
                    //Find the number of threads
                    //Thread number is in the first lin like "[X]"
                    final int start = list.indexOf((byte)'[');
                    final int end = list.indexOf((byte)']');

                    //Sanity check the bounds
                    if(! (end > start))
                    {
                        throw new IOException("Couldn't locate number of threads");
                    }

                    //Create a string from the Byte[] array subset
                    StringBuilder sb = new StringBuilder();
                    for(int i = start+1; i != end; ++i)
                    {                   
                        final char c = (char) buffer[i].byteValue();
                        sb.append(c);
                    }
                    String numThreadsStr = sb.toString();

                    //Try and parse the string into a number
                    try
                    {
                        this.numberOfThreads = Integer.valueOf(numThreadsStr);
                    }catch(NumberFormatException e)
                    {
                        throw new IOException("Number of threads is NaN",e);
                    }

                    //No more values to extract
                    foundInfoString = true;
                }

                //If the InputStream got EOF and the into string has not been found
                //Then an error has occurred. 
                if(result == -1 && ! foundInfoString )
                {
                    throw new IOException("Never got info string");
                }
            }

        }finally
        {
            //Close the connection
            conn.disconnect();
        }

    }

    public MotionHttpApi(String host,int port)
    {
        this.host = host;
        this.port = port;
    }
}

を呼び出すと、コードは正常に機能しますgetNumberOfCameras()。しかし、RetrieveSplash メソッドが複雑すぎるため、Java に関して何かを本当に理解している必要はないと思います。C なら 10 行ほど、Python なら 1 行で同じことができます。確かにJavaでバイトを操作するより健全な方法があるに違いありませんか?

整数の解析に失敗するたびに IOException をスローするべきではないなど、いくつかのスタイルの問題があると思います。しかし、それは別の問題です。

4

2 に答える 2

1

Gautam Tandon が提案したように最初の行を読んでから、正規表現を使用します。次に、正規表現が一致するかどうかを確認し、番号を簡単に抽出することもできます.

Regex' はhttp://txt2re.comで作成できます。私はすでにあなたのためにそれをしました。このページでは、作業用の Java、Pyhton、C などのファイルも作成されます。

// URL that generated this code:
// http://txt2re.com/index-java.php3?s=Motion%203.2.12%20Running%20[4]%20Threads&-7&-19&-5&-20&-1&2&-22&-21&-62&-63&15 

import java.util.regex.*;

class Main
{
  public static void main(String[] args)
  {
    String txt="Motion 3.2.12 Running [4] Threads";

    String re1="(Motion)";  // Word 1
    String re2="( )";   // White Space 1
    String re3="(3\\.2\\.12)";  // MMDDYY 1
    String re4="( )";   // White Space 2
    String re5="(Running)"; // Word 2
    String re6="( )";   // White Space 3
    String re7="(\\[)"; // Any Single Character 1
    String re8="(\\d+)";    // Integer Number 1
    String re9="(\\])"; // Any Single Character 2
    String re10="( )";  // White Space 4
    String re11="((?:[a-z][a-z]+))";    // Word 3

    Pattern p = Pattern.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10+re11,Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
    Matcher m = p.matcher(txt);
    if (m.find())
    {
        String word1=m.group(1);
        String ws1=m.group(2);
        String mmddyy1=m.group(3);
        String ws2=m.group(4);
        String word2=m.group(5);
        String ws3=m.group(6);
        String c1=m.group(7);
        String int1=m.group(8);
        String c2=m.group(9);
        String ws4=m.group(10);
        String word3=m.group(11);
        System.out.print("("+word1.toString()+")"+"("+ws1.toString()+")"+"("+mmddyy1.toString()+")"+"("+ws2.toString()+")"+"("+word2.toString()+")"+"("+ws3.toString()+")"+"("+c1.toString()+")"+"("+int1.toString()+")"+"("+c2.toString()+")"+"("+ws4.toString()+")"+"("+word3.toString()+")"+"\n");
    }
  }
}

//-----
// This code is for use with Sun's Java VM - see http://java.sun.com/ for downloads. 
//
// Paste the code into a new java application or a file called 'Main.java'
//
// Compile and run in Unix using:
// # javac Main.java 
// # java Main 
//

String int1=m.group(8);目的の整数を提供します。もちろん、上記のコードを単純化できます。今は冗長な方法です。

于 2013-07-11T12:36:31.673 に答える
0

BufferedReader を使用すると、retrieveSplash メソッドを大幅に簡素化できます。関数のより単純なバージョンを次に示します。

void retrieveSplash_simpler() throws IOException {
    URL url = new URL(getBaseUrl());
    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
    // open the connection
    conn.connect();
    // create a buffered reader to read the input stream line by line
    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

    // find number of threads
    String firstLine = reader.readLine();
    int x = firstLine.indexOf("[");
    int y = firstLine.indexOf("]");
    if (x > 0 && y > 0 && x < y) {
        try {
            numberOfThreads = Integer.parseInt(firstLine.substring(x+1, y));
        } catch (NumberFormatException nfe) {
            // disconnect and throw exception
            conn.disconnect();
            throw new IOException("Couldn't locate number of threads");
        }
    } else {
        // disconnect and throw exception
        conn.disconnect();
        throw new IOException("Couldn't locate number of threads");
    }

    // disconnect
    conn.disconnect();
}

その「conn.disconnect()」を複製する必要がないように、適切な場所で try/catch/finally ブロックを使用して、上記のメソッドをさらにクリーンアップします。しかし、単純にするためにここではそれを行いませんでした (try/catch/finally は時々トリッキーになります...)。

于 2013-04-01T19:53:28.743 に答える