Android Написання журналів до текстового файлу


129

Я намагаюся писати журнали в користувальницький файл Log.txt у файлі Android за допомогою цього коду Mine, але тоді цей метод створює файл, але нічого не містить. В основному я хочу прочитати попередній вміст файлу, а потім додати свої дані до наявного вмісту.

Кодекс такий:

public static void write(String str) 
    {
        InputStream fileInputStream = null;
        FileOutputStream fileOutpurStream = null;
        try
        { 
            fileInputStream = new FileInputStream(file);
            fileOutpurStream = new FileOutputStream(file);
            if(file.exists())
            {
                int ch = 0;
                int current = 0;
                StringBuffer buffer = new StringBuffer();
                while((ch = fileInputStream.read()) != -1)
                {
                    buffer.append((char) ch);
                    current++;
                }
                byte data[]=new byte[(int)file.length()];
                fileInputStream.read(data);   
                fileOutpurStream.write(data);
                fileOutpurStream.write(str.getBytes(),0,str.getBytes().length);
                fileOutpurStream.flush();
            } 
            else
            {   
                file.createNewFile();
                fileOutpurStream.write(str.getBytes(),0,str.getBytes().length);
                fileOutpurStream.flush();
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                fileInputStream.close();
                fileOutpurStream.flush();
                fileOutpurStream.close();
                fileOutpurStream = null;
                fileInputStream = null;
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

Відповіді:


247

Сподіваюся, що це може допомогти ...

public void appendLog(String text)
{       
   File logFile = new File("sdcard/log.file");
   if (!logFile.exists())
   {
      try
      {
         logFile.createNewFile();
      } 
      catch (IOException e)
      {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }
   try
   {
      //BufferedWriter for performance, true to set append to file flag
      BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); 
      buf.append(text);
      buf.newLine();
      buf.close();
   }
   catch (IOException e)
   {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
}

83
Не забудьте додати дозвіл на write_external_storage в Manifest!
virusss8

5
Мені потрібно було додати buf.flush (); beforebuf.close (); але функція tjis була саме тим, що мені було потрібно. дякую
Csabi

1
звідки я повинен викликати цю функцію, щоб вона записала весь файл входу програми ???
uniruddh

10
Я рекомендую переструктурувати код так, щоб buf.close()він знаходився всередині finallyблоку.
Вільям Прайс

2
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />що, звичайно, означало @ virusss8.
Бенгт

29

Для тих, хто не входить до журналу Java взагалі та до журналу Android

  1. Log4j - це загальна реалізація журналу Java, і зараз є проектом фундаменту програмного забезпечення Apache. Він не є специфічним для Android і тому має деякі несумісності з Android.
  2. SL4J не є реалізацією журналу, це шар абстракції. Це допомагає уникнути таких ситуацій, як залежність кожної сторонньої бібліотеки від проекту, намагаючись використовувати власну реалізацію журналу, як Log4j. Джерело .

Нижче наведено деякі варіанти входу в txt в Android

  1. Використовуйте logcat -fяк у цій відповіді для входу в файл. Зауважте, що з Android 4.2 дозвіл READ_LOGS не має жодного впливу, і кожна програма (якщо телефон не вкорінена) могла читати лише свої власні журнали. Недоліком тут є буфер logcat - круговий і має обмеження розміру. Ви не можете отримати попередні журнали.
  2. Використовуйте microlog4android (написаний для мобільних пристроїв, таких як Android), як у попередній відповіді . Може бути спосіб, але я не міг зрозуміти, як використовувати microlog4Android для входу в систему для внутрішнього сховища програми. Єдиним варіантом для шляху до журналів було зовнішнє сховище типу sdcard, тому я не міг його використовувати.
  3. Використовуйте Log4j з android-logging-log4j . Що робить android-logging-log4j? Це полегшує використання Log4j в Android, надаючи дві функції.

    • можливість відправити журнали до logcat на додаток до файлу реєстрації
    • простий спосіб встановити параметри конфігурації Log4j, такі як шлях до файлу, максимальний розмір файлу, кількість резервних копій тощо, надаючи клас LogConfigurator.

    Простий приклад нижче. Зауважте, що loggerоб’єктом у наведеному нижче прикладі є повернутий об’єкт Log4j, а не клас android-logging-log4j. Отже, android-logging-log4j використовується лише для налаштування Log4j.

  4. І все-таки спробувати LogBack . LogBack розроблений тією ж особою, яка придумала бібліотеки Log4J 1.x та SL4J. Не пов’язаний із Log4j 2.x, хоча.

Кроки щодо використання Log4j в Android.

  1. Додайте як log4j-1.2.x.jar, так і android-logging-log4j-1.0.3.jar у папку libs.

  2. Додайте дозволи лише у випадку використання зовнішнього сховища
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  3. Напишіть Log4jклас помічників

    package com.example.logger;
    
    import android.os.Environment;
    import de.mindpipe.android.logging.log4j.LogConfigurator;
    
    public class Log4jHelper {
        private final static LogConfigurator mLogConfigrator = new LogConfigurator();
    
        static {
            configureLog4j();
        }
    
        private static void configureLog4j() {
            String fileName = Environment.getExternalStorageDirectory() + "/" + "log4j.log";
            String filePattern = "%d - [%c] - %p : %m%n";
            int maxBackupSize = 10;
            long maxFileSize = 1024 * 1024;
    
            configure( fileName, filePattern, maxBackupSize, maxFileSize );
        }
    
        private static void configure( String fileName, String filePattern, int maxBackupSize, long maxFileSize ) {
            mLogConfigrator.setFileName( fileName );
            mLogConfigrator.setMaxFileSize( maxFileSize );
            mLogConfigrator.setFilePattern(filePattern);
            mLogConfigrator.setMaxBackupSize(maxBackupSize);
            mLogConfigrator.setUseLogCatAppender(true);
            mLogConfigrator.configure();
    
        }
    
        public static org.apache.log4j.Logger getLogger( String name ) {
            org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger( name );
            return logger;
        }
    }
  4. У класі діяльності

    org.apache.log4j.Logger log= Log4jHelper.getLogger( "YourActivity" );
    log.error("Error");
    log.info("Info");
    log.warn("Warn");

Приклад Джерело . Зауважте, що log4j 2.x (покращені функціональні можливості), переписані з нуля, не сумісні з назад з log4j 1.x. Тож вам доведеться використовувати jar4j 1.2.x jar з android-logging-log4j jar. Я зміг увійти до внутрішнього файлу програми та пізніше надіслати файл електронною поштоюsetReadable(true, false)


24

microlog4android працює для мене, але документація досить бідна. Все, що їм потрібно додати, - це підручник із швидкого початку .

Ось короткий підручник, який я знайшов.

  1. Додайте таку статичну змінну у свою основну діяльність:

    private static final Logger logger = LoggerFactory.getLogger();
  2. Додайте до свого onCreate()методу наступне :

    PropertyConfigurator.getConfigurator(this).configure();
  3. Створіть файл з назвою microlog.propertiesта збережіть його в assetsкаталозі

  4. Відредагуйте microlog.propertiesфайл так:

    microlog.level=DEBUG
    microlog.appender=LogCatAppender;FileAppender
    microlog.formatter=PatternFormatter
    microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
  5. Додайте такі оператори журналу:

    logger.debug("M4A");

Для кожного класу ви створюєте об’єкт реєстратора, як зазначено в 1)

6.Ви можете додати такий дозвіл:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Ось джерело для підручника


4
FileAppender створить файл "microlog.txt" на вашій sdcard (повний шлях у моєму випадку "/sdcard/microlog.txt)."
Руслан Янчишин

2
Цей швидкий посібник повинен бути частиною офіційної документації Microlog4Android.
Йохан Карлссон

Помилка: Android Dex: [проект] com.android.dex.DexException: Кілька файлів dex визначають Lcom / google / code / microlog4android / Level; ?

10

Попередження: я можу вас абсолютно не розуміти, але якщо все, що вам потрібно, це файл журналу, навіщо потіти?

Помістіть це у файл bat (змініть шлях до каталогу ваших інструментів, і yourappname, звичайно, назва вашої програми):

cd "C:\devAndroid\Software\android-sdk-windows-1.6_r1\android-sdk-windows-1.6_r1\tools"
adb logcat -v time   ActivityManager:W  yourappname:D  *:W >"C:\devAndroid\log\yourappname.log"

Тоді у своєму коді просто зробіть щось подібне до цього:

Log.d("yourappname", "Your message");

Щоб створити журнал, підключіть USB-кабель та запустіть файл bat.

З повагою


Не забудьте імпортувати android.util.Log.
Spidey

Він повертає "помилка: більше одного пристрою та емулятора - очікування пристрою -" і нічого більше. Щось не так?
ерос

20
Як це працює, якщо ви не поруч із ПК під час роботи програми?
DDSports

@DDSповідомляє, що це не так. Але він не зрозумів суті питання
Евокс

@DDSports ви можете використовувати adb через wifi.
Даніель Ф

8

Використовуйте slf4android lib.
Це проста реалізація api slf4j за допомогою Android java.util.logging. *.

Особливості:

  • вхід у файл, щоб вийти з поля
  • вхід до будь-якого іншого пункту призначення LoggerConfiguration.configuration().addHandlerToLogger
  • струсіть свій пристрій, щоб надсилати журнали зі скріншотом електронною поштою
  • насправді невеликий, він також занадто ~ 55 кБ

slf4android підтримується в основному @miensol .

Детальніше про slf4android читайте на нашому блозі:


7

Слід поглянути на microlog4android. У них є рішення, готове до входу у файл.

http://code.google.com/p/microlog4android/


12
Це здається гарною бібліотекою, але документація жахлива. Я просто не міг зрозуміти, як змусити його працювати, і в кінцевому підсумку сам щось склав.
Пол Ламмертсма

@PaulLammertsma: Я думаю, було б непогано, щоб ви внесли свій внесок у Microlog4Android. FYI: він має той же API, що і Log4j. Вибачте за погану документацію.
Йохан Карлссон

@Paul Lammertsma Як же БУДЕ БУДЕ добре, якщо документація така погана, що ви не можете її використовувати? Якщо ви не можете змусити його працювати, це лайно.
Неймовірний

7

Це може бути пізно, але сподіваюся, що це може допомогти. Спробуйте це ....

public void writefile()
    {
        File externalStorageDir = Environment.getExternalStorageDirectory();
        File myFile = new File(externalStorageDir , "yourfilename.txt");

        if(myFile.exists())
        {
           try
           {

        FileOutputStream fostream = new FileOutputStream(myFile);
        OutputStreamWriter oswriter = new OutputStreamWriter(fostream); 
        BufferedWriter bwriter = new BufferedWriter(oswriter);   
        bwriter.write("Hi welcome ");
        bwriter.newLine();            
        bwriter.close(); 
        oswriter.close(); 
        fostream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
        else
        {
            try {
                myFile.createNewFile();
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
        }

тут bfwritter.newlineзаписує ваш текст у файл. І додати дозвіл

 <uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"/>

у вашому файлі маніфесту безвідмовно.


6

Я вирішив цю проблему за допомогою наступного фрагмента коду в командному рядку:

File outputFile = new File("pathToFile"); 
Runtime.getRuntime().exec("logcat -c");
Runtime.getRuntime().exec("logcat -v time -f " + outputFile.getAbsolutePath())

Якщо параметр "час" додає деталі поля метаданих про дату, час виклику, пріоритет / тег та PID процесу видачі повідомлення.

Тоді у своєму коді просто зробіть щось подібне до цього (використовуючи android.util.Log):

Log.d("yourappname", "Your message");

4
Приємно працює при adbпідключенні, але не працює, коли пристрій перебуває в автономному режимі. Я б не використовував це у виробництві, але це просте рішення в режимі налагодження.
Жульєн Кронегг

2

Як правило, перед відкриттям потоку ви повинні мати ручку файлу. У вас є ручка fileOutputStream перед створеннямNewFile () у блоці else. Потік не створює файл, якщо його не існує.

Насправді не андроїд, але це дуже багато для цієї мети. Що робити, якщо робити багато операцій "запису" одна за одною? Ви будете читати весь вміст і записувати весь вміст, забираючи час і, що ще важливіше, час автономної роботи.

Я пропоную використовувати java.io.RandomAccessFile, шукайте () до кінця, а потім напишітьChars (), щоб додати. Це буде набагато чистіший код і, ймовірно, набагато швидше.


2

Я створив простий, легкий клас (близько 260 LoC), який розширює стандартну реалізацію android.util.Log за допомогою файлів журналу:
Кожне повідомлення журналу реєструється через android.util.Log, а також записується у текстовий файл на пристрої.

Ви можете знайти його на github:
https://github.com/volkerv/FileLog


1
не зробиш те, що нам потрібно для того, щоб операції з файлами не виконувалися на потоці інтерфейсу користувача. Якщо у нас є величезна кількість файлів?
Джейсіл Дейв

2

Після довгого розслідування я виявив, що:

  • android.util.Log за замовчуванням java.util.logging.Logger
  • LogCat використовує loggerз ім'ям "", щоб отримати примірник його використанняLogManager.getLogManager().getLogger("")
  • Android Devices додає до loggerекземпляра LogCat com.android.internal.logging.AndroidHandlerпісля запуску програм налагодження
  • Але !!! com.android.internal.logging.AndroidHandlerдрукує повідомлення на logcat лише з рівнями більше, ніж java.util.logging.Level.INFOнаприклад ( Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF)

Отже, писати журнали до файлу просто на rootLogger "" додавання java.util.logging.FileHandler:

  class App : Application{
    override fun onCreate() {
      super.onCreate()
      Log.d(TAG, printLoggers("before setup"))

      val rootLogger = java.util.logging.LogManager.getLogManager().getLogger("")
      val dirFile = destinationFolder
      val file = File(dirFile,"logFile.txt")
      val handler = java.util.logging.FileHandler(file.absolutePath, 5* 1024 * 1024/*5Mb*/, 1, true)
      handler.formatter = AndroidLogFormatter(filePath = file.absolutePath)

      rootLogger?.addHandler(handler)

      Log.d(TAG, printLoggers("after setup"))
    }
  }

val destinationFolder: File
        get() {
            val parent = 
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absoluteFile
            val destinationFolder = File(parent, "MyApp")
            if (!destinationFolder.exists()) {
                destinationFolder.mkdirs()
                destinationFolder.mkdir()
            }
            return destinationFolder
        }
class AndroidLogFormatter(val filePath: String = "", var tagPrefix: String = "") : Formatter() {

    override fun format(record: LogRecord): String {
        val tag = record.getTag(tagPrefix)
        val date = record.getDate()
        val level = record.getLogCatLevel()
        val message = record.getLogCatMessage()
        return "$date $level$tag: $message\n"
    }
}

fun LogRecord.getTag(tagPrefix: String): String {
    val name = loggerName
    val maxLength = 30
    val tag = tagPrefix + (if (name.length > maxLength) name.substring(name.length - maxLength) else name)
    return tag
}

fun LogRecord.getDate(): String? {
    return Date(millis).formatedBy("yyyy-MM-dd HH:mm:ss.SSS")
}

fun Date?.formatedBy(dateFormat: String): String? {
    val date = this
    date ?: return null
    val writeFormat = SimpleDateFormat(dateFormat, Locale.getDefault()) //MM в HH:mm
    return writeFormat.format(date)
}

fun LogRecord.getLogCatMessage(): String {
    var message = message

    if (thrown != null) {
        message += Log.getStackTraceString(thrown)
    }
    return message
}

fun Int.getAndroidLevel(): Int {
    return when {
        this >= Level.SEVERE.intValue() -> { // SEVERE
            Log.ERROR
        }
        this >= Level.WARNING.intValue() -> { // WARNING
            Log.WARN
        }
        this >= Level.INFO.intValue() -> { // INFO
            Log.INFO
        }
        else -> {
            Log.DEBUG
        }
    }
}

fun LogRecord.getLogCatLevel(): String {
    return when (level.intValue().getAndroidLevel()) {
        Log.ERROR -> { // SEVERE
            "E/"
        }
        Log.WARN -> { // WARNING
            "W/"
        }
        Log.INFO -> { // INFO
            "I/"
        }
        Log.DEBUG -> {
            "D/"
        }
        else -> {
            "D/"
        }
    }
}

fun getLoggerLevel(level: Int): Level {
    return when (level) {
        Log.ERROR -> { // SEVERE
            Level.SEVERE
        }
        Log.WARN -> { // WARNING
            Level.WARNING
        }
        Log.INFO -> { // INFO
            Level.INFO
        }
        Log.DEBUG -> {
            Level.FINE
        }
        else -> {
            Level.FINEST
        }
    }
}

Щоб надрукувати всі реєстратори у вашому додатку:

Log.e(TAG, printLoggers("before setup"))

 private fun printLoggers(caller: String, printIfEmpty: Boolean = true): String {
        val builder = StringBuilder()
        val loggerNames = LogManager.getLogManager().loggerNames
        builder.appendln("--------------------------------------------------------------")
        builder.appendln("printLoggers: $caller")
        while (loggerNames.hasMoreElements()) {
            val element = loggerNames.nextElement()
            val logger = LogManager.getLogManager().getLogger(element)
            val parentLogger: Logger? = logger.parent
            val handlers = logger.handlers
            val level = logger?.level
            if (!printIfEmpty && handlers.isEmpty()) {
                continue
            }
            val handlersNames = handlers.map {
                val handlerName = it.javaClass.simpleName
                val formatter: Formatter? = it.formatter
                val formatterName = if (formatter is AndroidLogFormatter) {
                    "${formatter.javaClass.simpleName}(${formatter.filePath})"
                } else {
                    formatter?.javaClass?.simpleName
                }
                "$handlerName($formatterName)"
            }
            builder.appendln("level: $level logger: \"$element\" handlers: $handlersNames parentLogger: ${parentLogger?.name}")
        }
        builder.appendln("--------------------------------------------------------------")
        return builder.toString()
    }

Привіт. У чому полягає користь використання цього "" реєстратора. Я не бачу різниці зі спеціальним реєстратором. чи я щось пропускаю?
Абінс Шаджі

1

Цей варіант набагато коротший

спробуйте {
    остаточний шлях до файлу = новий файл (
            Environment.getExternalStorageDirectory (), "DBO_logs5");
    if (! path.exists ()) {
        шлях.mkdir ();
    }
    Runtime.getRuntime (). Exec (
            "logcat -d -f" + шлях + File.separator
                    + "dbo_logcat"
                    + ".txt");
} лов (IOException e) {
    e.printStackTrace ();
}

1

Ви можете використовувати бібліотеку, яку я написав. Це дуже просто у використанні:

Додайте цю залежність у файл gradle:

dependencies {
    compile 'com.github.danylovolokh:android-logger:1.0.2'
}

Ініціалізуйте бібліотеку в класі програми:

File logsDirectory = AndroidLogger.getDefaultLogFilesDirectory(this);
    int logFileMaxSizeBytes = 2 * 1024 * 1024; // 2Mb
    try {
        AndroidLogger.initialize(
                this,
                logsDirectory,
                "Log_File_Name",
                logFileMaxSizeBytes,
                false
                );
    } catch (IOException e) {
        // Some error happened - most likely there is no free space on the system
    }

Ось як ви користуєтеся бібліотекою:

AndroidLogger.v("TAG", "Verbose Message");

Ось як отримати журнали:

AndroidLogger.processPendingLogsStopAndGetLogFiles(new AndroidLogger.GetFilesCallback() {
        @Override
        public void onFiles(File[] logFiles) {
            // get everything you need from these files
            try {
                AndroidLogger.reinitAndroidLogger();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

Ось посилання на сторінку github з додатковою інформацією: https://github.com/danylovolokh/AndroidLogger

Сподіваюся, це допомагає.


1

Багато попередніх версій log4j не працюють зараз (05/2019). Але ви можете використовувати Hyperlog - я можу підтвердити, що він працює.

  1. Додайте цей рядок до проекту залежностей та синхронізації

    implementation 'com.hypertrack:hyperlog:0.0.10'
  2. Створіть новий клас додатків (створіть новий клас java та розгорніть програму). Потім в метод onCreate додайте ці рядки:

    HyperLog.initialize(this);
    HyperLog.setLogLevel(Log.VERBOSE);
    
    HyperLog.getDeviceLogsInFile(this);
  3. Змініть файл маніфесту, щоб він визначив файл програми.

    <application
        android:name=".AppClass"
        .....
  4. Різні способи входу в систему:

    HyperLog.d(TAG,"debug");
    HyperLog.i(TAG,"information");
    HyperLog.e(TAG,"error");
    HyperLog.v(TAG,"verbose");
    HyperLog.w(TAG,"warning");
    HyperLog.a(TAG,"assert");
    HyperLog.exception(TAG,"exception",throwable);
  5. Знайдіть файли журналів. Перейдіть до

    RootFolder/android/data/"appPackageName/LogFiles/

Я спробував цю бібліотеку у файлі, створеному з HyperLog.getDeviceLogsInFile (це); там є лише останній створений журнал
mad_greasemonkey
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.