Odczyt Pliku Binarnego dev/inputs/js w Java

0

Witam Temat odczytu plików w Linux. Są to pliki dość nietypowe, to znaczy przechowują dane wejścia z urządzeń. Akurat pliki js odpowiadają za rożnego rodzaju kontrolery np pady.

Struktura pliku takiego pliku jest zapisana mniej więcej w ten sposób.

struct js_event {
    __u32 time;     /* event timestamp in milliseconds */
    __s16 value;    /* value */
    __u8 type;      /* event type */
    __u8 number;    /* axis/button number */
};

Czyli łącznie 8 bajtów
podczas otwarcia pliku jest około 160 bajtów inicjalizacji informacji.
natomiast dalej są dane przekazywane jak w strukturze.
Mój kod wygląda mniej więcej tak.

public static void main(String[] args) throws FileNotFoundException, IIOException {
        System.out.println("test");
        try {
            
            FileInputStream f = new FileInputStream("/dev/input/js1");
            BufferedInputStream bf = new BufferedInputStream(f);
            while (true) {

                byte[]  x= bf.readNBytes(8);


                if (x[7]==-1) break;


                else {

                    System.out.println(test(x));
                }
            }
            f.close();
        }
        catch (IOException e) {
            System.err.println("Błąd " + e);
        }

    }

Nie ma tutaj funkcji test ale zwraca ona liste [Time , Value, Typ, Numer,]
Ogólnie kod działa ale..
Plik jest dość specyficzny to znaczy tak jak by był nieskończony ale jednocześnie zerowy :D nie wiem jak to wytłumaczyć.
Nie da się zakończyć odczytywania a jednocześnie zakończenie odczytywania pliku nie jest mi na rękę bo ponowne otwarcie wypluje znowu 160 bajtów niepotrzebnych mi danych.
Plik odczytuje paczki po 8 bajtów ale te 8 bajtów pojawia się dopiero jak kontroler coś prześle co skutkuje zatrzymaniem programu i czekaniem aż pojawi się 8 bajtów do odczytu.
czyli jak bym umieścił dalszą część programu poniżej .

byte[]  x= bf.readNBytes(8);

to zostanie dopiero wykonane jak pojawią się dane z kontrolera. Czyli trochę niedopuszczalne.
Myślałem o jakimś wskaźniku albo markerze ale w przepadku tego pliku to nie działa. (albo źle to robię)
Jakie macie pomysły aby program wykonywał się dalej pomimo że w pliku nie ma nic do odczytania?
Albo zrobić osobą funkcję lub klasę w jakimś innym wątku która będzie się wykonywała niezależnie (cały czas) i raportowała różne zdarzenia w zmiennych swojej klasy?.
Jednak w Javie jestem bardzo początkujący i nie wiem czy to możliwe.
Proszę o jakieś sugestie.

1

Możesz popatrzeć na: https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#available(), tyle że to może nie działać z BufferedInputStream.

Jeżeli nie chcesz czekać to możesz to zrobić asynchronicznie korzystając z java.nio, alternatywnie odpal wątek który będzie to czytał w pętli czekając i umieszczał odczytane dane w jakiejś kolejce np. ConcurrentLinkedQueue lub wrzucał odczytane zdarzenia na jakiegoś executora.

Java NIO to nie jest najprzyjemniejsze w użyciu API. Generalnie użyj kodu stąd: https://examples.javacodegeeks.com/core-java/nio/channels/selector-channels/java-nio-channels-selector-example/
Tylko zamiast Socket...Channel użyj FileChannel: https://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html https://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousFileChannel.html

https://docs.oracle.com/javase/7/docs/api/java/io/DataInputStream.html - Może też pomóc (ale sprawdź czy to ma odpowiedni endianness).

EDIT: Wygląda na to (https://www.baeldung.com/java-nio2-async-file-channel) że nie sposób użyć XXXFileChannel z Selektorem Java.NIO - można więc albo jechać na czystym AsyncFileChannel albo czekać w wątku.

0

@Wikingus: pytanie co chcesz osiągnąć.
Jeśli chcesz robić coś synchronicznie (np. odczytaj następny element, zapisz do bazy danych) to zamknij odczyt w oddzielnej klasie i wyrzuć while(true) .
Jeśli chcesz coś robić w międzyczasie innego (np. wyświetlanie najnowszego wyniku z kontrolera na jakimś UI, który działa niezależnie) to zamknij odczyt w oddzielnej klasie, dodaj handler:

private void read(final Consumer<String> handler) {
        try {

            FileInputStream f = new FileInputStream("/dev/input/js1");
            BufferedInputStream bf = new BufferedInputStream(f);
            while (true) {
                byte[]  x= bf.readNBytes(8);
                if (x[7]==-1) break;

                else {
                    handler.accept(test(x));
                }
            }
            f.close();
        }
        catch (IOException e) {
            System.err.println("Błąd " + e);
        }
    }

i wykonaj go asynchronicznie używając np. ForkJoinPool, ExecutorService lub Thread.

0

Witam Dziękuję za szybką odpowiedź.
Java trochę mnie przygniata próbuje w niej pisać dopiero 2-3 dni i to tylko krótki czas.
Dawno Dawno temu pisałem w C i C++ ale obiektów dosłownie tylko liznąłem. Sama struktura pisania kodu w klasie wydaje się trochę odjechana. Porostu to co piszecie muszę spokojnie przetrawić.
Spróbuję rozwiązania z kilkoma wątkami bo to mi wydaje się najprostsze aczkolwiek mogę mieć rację i tylko mi się wydaje. Nie jestem Pewien co to handler czy to coś jak wskaźnik do danego obiektu?.
Ogólnie próbuję stworzyć klasę obsługi pada klasę. Natomiast czy mogę w programie głównym stworzyć obiekt pracować na nim ale jedną metodę bardzo chciałbym odpalić w innym wątku ale metodę tego obiektu który stworzyłem w programie głównym. Czyli np.

Pad Padzik1 = new Pad();
//tutaj reszta programu pewnie w pętli 
while(true) {
 to w innym wątku Padzik1.OdczytDanych();
a to w normalnym wątku;

}


Czy mniej więcej tak to może wyglądać?

Ok udało mi się na wątkach zrobiłem to mniej więcej tak (podany przykład operuje na zwykłym wydrukowaniu teksu w terminali i nie robi nic oprócz tego ze działa niezależnie ale sama koncepcja się sprawdziła.)

public class test {
    public static void main(String[] args) {

    }

    public static void OdczytJS () throws InterruptedException{
        for (int i = 0; i < 1000; i++) {
            System.out.println("Odczytuje sobie JS i9 Wrzucam do zmiennaj BLE");
            Thread.sleep(1000);
        }

    }
    public static void OdczytEvent() throws InterruptedException{
        for (int i = 0; i < 1000; i++) {
            System.out.println("Tutaj odczytuje Event i zapisuje do bluasdfa");
            Thread.sleep(200);
        }
    }

    public void StartWatkow() throws  InterruptedException{

        Thread watek1 = new Thread(() -> {
            try {
                OdczytJS();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread watek2 = new Thread(() -> {
            try {
                OdczytEvent();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        watek1.start();
        watek2.start();

    }
}

A klasa główna programu

public class KolorRGB {
    public static void main(String[] args) throws  InterruptedException{
        test pad = new test();
        pad.StartWatkow();

        while (true){

            for (int j = 0; j < 20; j++) {
                System.out.println("test "+j);
                Thread.sleep(500);
            }


        }
    }


}

Jak dokończę klasę obsługi pada to wrzucę bardzo chętnie na formom może się komuś kiedyś przyda.

Nie wiem jak zmienić temat postu ale jak jakiś moderator może dorzucić ("wielowątkowość" to może się to kiedyś komuś przydać bo mimo wszytko rozwiązanie zostało oparte na wielowątkowości. Pewnie topornie ale działa.)

1 użytkowników online, w tym zalogowanych: 0, gości: 1