【问题标题】:Android Writing Logs to text FileAndroid将日志写入文本文件
【发布时间】:2010-12-17 21:31:57
【问题描述】:

我正在尝试使用我的此代码将日志写入 Android 文件上的自定义 Log.txt 文件,但随后此方法会创建文件但不包含任何内容。基本上我想读取文件的先前内容,然后将我的数据附加到现有内容中。

代码如下:

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();
            }
        }

【问题讨论】:

    标签: android


    【解决方案1】:

    一般来说,在打开流之前必须有一个文件句柄。您在 else 块中有一个 fileOutputStream 句柄 before createNewFile() 。如果文件不存在,则流不会创建文件。

    不是真正的 android 特定的,但为此目的需要大量的 IO。如果您一个接一个地执行许多“写”操作怎么办?您将阅读全部内容并编写全部内容,需要时间,更重要的是,电池寿命。

    我建议使用 java.io.RandomAccessFile,seek()'ing 到最后,然后 writeChars() 追加。这将是更简洁的代码,并且可能会更快。

    【讨论】:

      【解决方案2】:

      警告:我可能完全误解了你,但如果你想要的只是一个日志文件,为什么要出汗?

      把这个放到一个bat文件里(把路径改成你的tools目录,你的appname当然就是你的app的名字):

      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。
      • 它返回“错误:多个设备和模拟器 - 等待设备 -”,仅此而已。有什么问题吗?
      • 如果您在运行应用程序时不在 PC 附近,这将如何工作?
      • @DDSports 它没有。但他不明白问题的本质
      • @DDSports 你可以通过 wifi 使用 adb。
      【解决方案3】:

      你应该看看 microlog4android。他们有一个准备好记录到文件的解决方案。

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

      【讨论】:

      • 这似乎是一个不错的库,但文档很糟糕。我根本不知道如何让它发挥作用,最后我自己组装了一些东西。
      • @PaulLammertsma:我认为你为 Microlog4Android 做出贡献会很好。仅供参考:它具有与 Log4j 相同的 API。抱歉文档不好。
      • @Paul Lammertsma 如果它的文档那么糟糕,你不能使用它,那怎么可能是好的?如果你不能让它工作,那就是废话。
      【解决方案4】:

      希望这可以帮助...

      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();
         }
      }
      

      【讨论】:

      • 不要忘记在 Manifest 中添加 write_external_storage 权限!
      • 我需要添加 buf.flush(); beforebuf.close();但 tjis 功能正是我所需要的。谢谢
      • 我应该从哪里调用这个函数,以便它写入所有应用程序的登录文件???
      • 我建议重构代码,使buf.close() 位于finally 块内。
      • <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 当然是@virusss8 的意思。
      【解决方案5】:

      microlog4android 对我有用,但文档很差。他们需要补充的是这是一个快速入门tutorial

      这是我找到的一个快速教程。

      1. 在您的主 Activity 中添加以下静态变量:

        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" />
      

      这里是source 教程

      【讨论】:

      • FileAppender 将在您的 sdcard 上创建一个文件“microlog.txt”(在我的情况下,完整路径是“/sdcard/microlog.txt”)。
      • 这个快速教程应该是Microlog4Android官方文档的一部分。
      • Error:Android Dex: [project] com.android.dex.DexException: Multiple dex files defined Lcom/google/code/microlog4android/Level; ?
      【解决方案6】:

      这可能会迟到,但希望这可能会有所帮助.. 试试这个....

      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"/>
      

      在你的清单文件中没有失败。

      【讨论】:

        【解决方案7】:

        我以命令行方式通过以下代码解决了这个问题:

        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");
        

        【讨论】:

        • 在连接adb 时工作良好,但在设备处于独立模式时无法工作。我不会在生产中使用它,但它是调试模式下的简单解决方案。
        【解决方案8】:

        对于一般 Java 日志记录和 Android 日志记录的新手

        1. Log4j 是通用的 java 日志实现,现在是 Apache 软件基础。它不是特定于 Android 的,所以也有 与 Android 存在一些不兼容问题。
        2. SL4J 不是日志实现,它是一个抽象层。它 有助于避免像每个 3rd 方库这样的情况 项目的依赖项,尝试使用自己的日志记录 像 Log4j 这样的实现。 Source

        在Android中记录到txt的一些选项如下

        1. 使用logcat -f 就像在这个answer 中一样记录到文件。请注意,从 Android 4.2,READ_LOGS 权限没有任何影响,并且每个 应用程序(除非手机已root)只能读取自己的日志。 这里的缺点是 logcat 缓冲区是循环的并且有大小 限制。您可能无法获得更早的日志。
        2. 使用microlog4android(为Android等移动设备编写)作为 在之前的answer。可能有办法,但我想不通,如何 使用 microlog4Android 记录到应用程序内部存储。 日志路径的唯一选择是像 sdcard 这样的外部存储,所以我 无法使用。
        3. Log4jandroid-logging-log4j 一起使用。做什么 android-logging-log4j 做什么?它使 Log4j 在 Android 中更易于使用 通过给出两个函数。

          • 除了日志文件之外还可以将日志发送到 logcat 的选项
          • 通过提供 LogConfigurator 类来设置 Log4j 配置选项(如文件路径、最大文件大小、备份数量等)的简单方法。

          下面的简单示例。请注意,下面示例中的 logger 对象是返回的 Log4j 对象,而不是 android-logging-log4j 类。所以android-logging-log4j只用于配置Log4j。

        4. 尚未尝试LogBack。 LogBack 是由同一个人开发的 提出了 Log4J 1.x 和 SL4J 库。与 Log4j 2.x 无关 不过。

        在 Android 中使用 Log4j 的步骤。

        1. log4j-1.2.x.jarandroid-logging-log4j-1.0.3.jar 添加到 libs 文件夹。

        2. 仅在使用外部存储时添加权限
          &lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/&gt;

        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");
          

        Example Source。请注意,从头开始重写的 log4j 2.x(改进的功能)不能与 log4j 1.x 向后兼容。因此,您必须将 log4j 1.2.x jar 与 android-logging-log4j jar 一起使用。我能够登录到应用程序内部文件,然后用setReadable(true, false)通过电子邮件发送文件

        【讨论】:

          【解决方案9】:

          使用slf4android 库。
          这是slf4j api使用android java.util.logging.*的简单实现。

          特点:

          • 开箱即用地记录到文件
          • LoggerConfiguration.configuration().addHandlerToLogger 登录到任何其他目的地
          • 摇动您的设备以通过电子邮件发送带有屏幕截图的日志
          • 真的很小,只需要 ~55kB

          slf4android主要由@miensol维护。

          在我们的博客上阅读更多关于 slf4android 的信息:

          【讨论】:

            【解决方案10】:

            我创建了一个简单的轻量级类(大约 260 LoC),它使用基于文件的日志记录扩展了标准 android.util.Log 实现:
            每条日志消息都通过 android.util.Log 记录,并写入设备上的文本文件。

            你可以在github上找到它:
            https://github.com/volkerv/FileLog

            【讨论】:

            • 别担心我们需要确保文件操作不在 UI 线程上完成。如果我们有大量的文件日志记录?
            【解决方案11】:

            这个变体要短得多

            尝试 { 最终文件路径 = 新文件( Environment.getExternalStorageDirectory(), "DBO_logs5"); 如果(!path.exists()){ 路径.mkdir(); } Runtime.getRuntime().exec( “logcat -d -f” + 路径 + File.separator +“dbo_logcat” + ".txt"); } 捕捉(IOException e){ e.printStackTrace(); }

            【讨论】:

              【解决方案12】:

              您可以使用我编写的库。 它非常易于使用:

              将此依赖项添加到您的 gradle 文件中:

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

              在 Application 类中初始化库:

              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

              希望对你有帮助。

              【讨论】:

                【解决方案13】:

                log4j 上的许多以前的版本现在都不起作用(05/2019)。但是您可以使用 Hyperlog - 我可以确认它有效。

                1. 将此行添加到您的依赖项和同步项目中

                  implementation 'com.hypertrack:hyperlog:0.0.10'
                  
                2. 创建一个新的应用程序类(创建一个新的 java 类并扩展 Application)。然后在 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(this); 生成的文件中;只有最后生成的日志在那里
                【解决方案14】:

                经过长时间的调查,我发现:

                • android.util.Log 默认使用 java.util.logging.Logger
                • Lo​​gCat 使用名称为""logger,获取它的实例使用LogManager.getLogManager().getLogger("")
                • Android 设备在运行调试应用程序后添加到 LogCat logger 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()
                    }
                

                【讨论】:

                • 嗨。使用这个“”记录器有什么好处。我认为自定义记录器没有区别。还是我错过了什么?
                • 我已经尝试过这个并得到 java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.logging.Logger java.util.logging.Logger.getParent()' on an null object reference .
                【解决方案15】:
                    File logFile = new File(filename);
                    try { 
                    Process process = Runtime.getRuntime().exec("logcat AndroidRuntime:E *:S 
                    -f " + logFile);
                    } 
                    catch ( Exception e ) 
                    { Basic.Logger("Error Basic", "error "+e); }
                

                试试这个代码在文件中写入错误日志

                【讨论】:

                  猜你喜欢
                  • 2012-01-16
                  • 2020-06-27
                  • 2013-01-20
                  • 2012-04-06
                  • 2023-03-31
                  • 2015-03-19
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多