Java操作Ant压缩和解压文件及批量打包Anroid应用

实现zip/tar的压缩与解压

java中实际是提供了对  zip等压缩格式的支持,但是为什么这里会用到ant呢?

原因主要有两个:
1. java提供的类对于包括有中文字符的路径,文件名支持不够好,你用其它第三方软件解压的时候就会存在乱码。而ant.jar就支持文件名或者路径包括中文字符。
2. ant.jar提供了强大的工具类,更加方便于我们对压缩与解压的操作。
注意事项:
1. 首先说明一下,关于皮肤或者类似于皮肤的Zip包,实际上公司可能会根据自己的规定或需求,自定义压缩包文件的结尾,实际上大多还是Zip包的格式. 具体部分的处理大致上是一样的,因此不再复述,本文给出的例子已经有Zip包和Tar包的解压缩.
2. 还有要注意的是,此处为提升理解,因此加入zip/tar压缩,解压的界面,实际应用中此部分无需单独的界面展示(解压缩需要一定时间的话,则为加强用户体验,加入提示框与进度条),请自行编写解压缩管理类进行逻辑判断分别处理.
3. 测试时需要讲要解压缩的包导入sdcard目录下(若为其他目录,请修改代码中路径)

2016226144353610.jpg (563×582)

程序主界面及解压缩的界面:

2016226144429500.jpg (369×473)

2016226144445346.jpg (332×440)

接下来是解压缩核心的代码:
布局文件: antzip.xml:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent"> 
   
   
  <LinearLayout 
    android:orientation="vertical" android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:gravity="center" 
    android:padding="20dip" 
    android:layout_centerInParent="true"> 
     
    <RadioGroup 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:orientation="horizontal"> 
      <RadioButton android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/radioZip" 
        android:checked="true" 
        android:text="ZIP"/> 
       
      <RadioButton android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/radioTar" 
        android:text="TAR" 
        android:layout_marginLeft="10dip"/> 
    </RadioGroup> 
     
    <Button android:text="压缩" android:id="@+id/button1" 
      android:layout_width="fill_parent" android:layout_height="wrap_content" 
      android:paddingLeft="30dip" android:paddingRight="30dip"></Button> 
    <Button android:text="解压" android:id="@+id/button2" 
      android:layout_width="fill_parent" android:layout_height="wrap_content" 
      android:paddingLeft="30dip" android:paddingRight="30dip" 
      android:layout_marginTop="20dip"></Button> 
  </LinearLayout> 
   
   
</RelativeLayout> 

AntZipActivity:

public class AntZipActivity extends Activity { 
  public static final String TYPE = "type"; 
  public static final int   TYPE_ZIP = -1; 
  public static final int   TYPE_TAR = 1; 
   
  public static final String SUFFIX_ZIP = ".zip"; 
  public static final String SUFFIX_TAR = ".tar"; 
  /** Called when the activity is first created. */ 
  private Button   btnDoCompress; 
  private Button   btnDecompress; 
   
  private RadioButton radioZip; 
  private RadioButton radioTar; 
   
  private boolean isZip = true; 
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.antzip); 
    radioZip = (RadioButton)findViewById(R.id.radioZip); 
    isZip = true; 
    radioZip.setChecked(true); 
    radioZip.setOnCheckedChangeListener(new OnCheckedChangeListener() { 
       
      @Override 
      public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) { 
        System.out.println("radioZip:"+isChecked); 
        if(isChecked) 
        { 
          isZip = true; 
        } 
      } 
    }); 
    radioTar = (RadioButton)findViewById(R.id.radioTar); 
    radioTar.setOnCheckedChangeListener(new OnCheckedChangeListener() { 
       
      @Override 
      public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) { 
        System.out.println("radioTar:"+isChecked); 
        if(isChecked) 
        { 
          isZip = false; 
        } 
      } 
    }); 
    btnDoCompress = (Button)findViewById(R.id.button1); 
    btnDoCompress.setOnClickListener(new OnClickListener() { 
       
      @Override 
      public void onClick(View v) { 
        //进入压缩界面  
        Intent i = new Intent(AntZipActivity.this,DozipActivity.class); 
        i.putExtra(TYPE,isZip?TYPE_ZIP:TYPE_TAR); 
        AntZipActivity.this.startActivity(i); 
      } 
    }); 
    btnDecompress = (Button)findViewById(R.id.button2); 
    btnDecompress.setOnClickListener(new OnClickListener() { 
       
      @Override 
      public void onClick(View v) { 
        //进入解压界面  
        Intent i = new Intent(AntZipActivity.this,UnzipActivity.class); 
        i.putExtra(TYPE,isZip?TYPE_ZIP:TYPE_TAR); 
        AntZipActivity.this.startActivity(i); 
      } 
    }); 
  } 
} 

DozipActivity:

public class DozipActivity extends Activity implements OnClickListener{ 
  private EditText etPath; 
  private EditText etDest; 
  private Button btnDozip; 
  private TextView  tvTip; 
   
  private String srcPath; 
  private String zipDest; 
   
  private int   type; 
  private String suffix; 
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setTitle("Ant-压缩"); 
    type = getIntent().getIntExtra(AntZipActivity.TYPE,AntZipActivity.TYPE_ZIP); 
    suffix = type==AntZipActivity.TYPE_ZIP ? AntZipActivity.SUFFIX_ZIP:AntZipActivity.SUFFIX_TAR; 
    setContentView(R.layout.dozip); 
    // 
    etPath = (EditText)findViewById(R.id.editText1); 
    etDest = (EditText)findViewById(R.id.editText2); 
    //设置一些默认的函数 
    etPath.setText("/sdcard/antzip"); 
    etDest.setText("/sdcard/antzip"+suffix); 
    btnDozip = (Button)findViewById(R.id.button); 
    tvTip  = (TextView)findViewById(R.id.tv_tip); 
    btnDozip.setOnClickListener(this); 
  } 
  @Override 
  public void onClick(View v) { 
    srcPath = etPath.getEditableText().toString(); 
    if(TextUtils.isEmpty(srcPath)) 
    { 
      Toast.makeText(this,"请指定一个路径",Toast.LENGTH_SHORT).show(); 
      return; 
    } 
    File srcFile = new File(srcPath); 
    if(!srcFile.exists()) 
    { 
      Toast.makeText(this,"指定的压缩包不存在",Toast.LENGTH_SHORT).show(); 
      return; 
    } 
    zipDest = etDest.getEditableText().toString(); 
    if(TextUtils.isEmpty(zipDest)) 
    { 
      //如果用户没有输入目标文件,则生成一个默认的 
      zipDest = srcFile.getParent(); 
    } 
    System.out.println("zip name:"+zipDest); 
    //如果是以/结尾的,则证明用户输入的是一个目录 ,需要在后面加上文件名 
    if(zipDest.endsWith(File.separator)) 
    { 
      zipDest+=srcFile.getName()+suffix; 
    } 
    else 
    { 
      //如果压缩文件名不是以zip/tar结尾,则加上后缀后 
      if(!zipDest.endsWith(suffix)) 
      { 
        zipDest +=suffix; 
      } 
    } 
    //如果用户选择的是zip,则用 zipUtil进行压缩 
    if(type == AntZipActivity.TYPE_ZIP) 
    { 
 
      ZipUtil zipp = new ZipUtil(); 
      zipp.doZip(srcPath,zipDest); 
    } 
    //如果用户选择的是tar,则用 tarUtil进行压缩 
    else 
    { 
      TarUtil tarr = new TarUtil(); 
      tarr.doTar(srcPath,zipDest); 
    } 
    //压缩完成后还是提示用户 
    tvTip.setText("压缩文件路径:"+zipDest); 
    Toast.makeText(this,"压缩完成",Toast.LENGTH_SHORT).show(); 
  } 
} 

解压缩工具类ZipUtil:

public class ZipUtil { 
  private ZipFile     zipFile;  
  private ZipOutputStream zipOut;   //压缩Zip  
  private int      bufSize;  //size of bytes  
  private byte[]     buf;  
 
  public ZipUtil(){ 
    //要构造函数中去初始化我们的缓冲区 
    this.bufSize = 1024*4;  
    this.buf = new byte[this.bufSize];  
  }  
    
  /** 
   * 对传入的目录或者是文件进行压缩 
   * @param srcFile 需要 压缩的目录或者文件 
   * @param destFile 压缩文件的路径 
   */ 
  public void doZip(String srcFile,String destFile) {// zipDirectoryPath:需要压缩的文件夹名 
    File zipFile = new File(srcFile); 
    try { 
      //生成ZipOutputStream,会把压缩的内容全都通过这个输出流输出,最后写到压缩文件中去 
      this.zipOut = new ZipOutputStream(new BufferedOutputStream( 
          new FileOutputStream(destFile))); 
      //设置压缩的注释 
      zipOut.setComment("comment"); 
      //设置压缩的编码,如果要压缩的路径中有中文,就用下面的编码 
      zipOut.setEncoding("GBK"); 
      //启用压缩  
      zipOut.setMethod(ZipOutputStream.DEFLATED);  
 
      //压缩级别为最强压缩,但时间要花得多一点  
      zipOut.setLevel(Deflater.BEST_COMPRESSION);  
       
      handleFile(zipFile,this.zipOut,""); 
      //处理完成后关闭我们的输出流 
      this.zipOut.close(); 
    } catch (IOException ioe) { 
      ioe.printStackTrace(); 
    } 
  } 
 
  /** 
   * 由doZip调用,递归完成目录文件读取 
   * @param zipFile 
   * @param zipOut 
   * @param dirName 这个主要是用来记录压缩文件的一个目录层次结构的 
   * @throws IOException 
   */ 
  private void handleFile(File zipFile,ZipOutputStream zipOut,String dirName) throws IOException { 
    System.out.println("遍历文件:"+zipFile.getName()); 
    //如果是一个目录,则遍历 
    if(zipFile.isDirectory()) 
    { 
      File[] files = zipFile.listFiles(); 
 
      if (files.length == 0) {// 如果目录为空,则单独创建之. 
        //只是放入了空目录的名字 
        this.zipOut.putNextEntry(new ZipEntry(dirName+zipFile.getName()+File.separator)); 
        this.zipOut.closeEntry(); 
      } else {// 如果目录不为空,则进入递归,处理下一级文件 
        for (File file : files) { 
          // 进入递归,处理下一级的文件 
          handleFile(file,zipOut,dirName+zipFile.getName()+File.separator); 
        } 
      } 
    } 
    //如果是文件,则直接压缩 
    else 
    { 
      FileInputStream fileIn = new FileInputStream(zipFile); 
      //放入一个ZipEntry 
      this.zipOut.putNextEntry(new ZipEntry(dirName+zipFile.getName())); 
      int length = 0; 
      //放入压缩文件的流 
      while ((length = fileIn.read(this.buf)) > 0) { 
        this.zipOut.write(this.buf,length); 
      } 
      //关闭ZipEntry,完成一个文件的压缩 
      this.zipOut.closeEntry(); 
    } 
     
  } 
 
  /** 
   * 解压指定zip文件 
   * @param unZipfile 压缩文件的路径 
   * @param destFile   解压到的目录  
   */ 
  public void unZip(String unZipfile,String destFile) {// unZipfileName需要解压的zip文件名 
    FileOutputStream fileOut; 
    File file; 
    InputStream inputStream; 
 
    try { 
      //生成一个zip的文件 
      this.zipFile = new ZipFile(unZipfile); 
      //遍历zipFile中所有的实体,并把他们解压出来 
      for (@SuppressWarnings("unchecked") 
      Enumeration<ZipEntry> entries = this.zipFile.getEntries(); entries 
          .hasMoreElements();) { 
        ZipEntry entry = entries.nextElement(); 
        //生成他们解压后的一个文件 
        file = new File(destFile+File.separator+entry.getName()); 
 
        if (entry.isDirectory()) { 
          file.mkdirs(); 
        } else { 
          // 如果指定文件的目录不存在,则创建之. 
          File parent = file.getParentFile(); 
          if (!parent.exists()) { 
            parent.mkdirs(); 
          } 
          //获取出该压缩实体的输入流 
          inputStream = zipFile.getInputStream(entry); 
 
          fileOut = new FileOutputStream(file); 
          int length = 0; 
          //将实体写到本地文件中去 
          while ((length = inputStream.read(this.buf)) > 0) { 
            fileOut.write(this.buf,length); 
          } 
          fileOut.close(); 
          inputStream.close(); 
        } 
      } 
      this.zipFile.close(); 
    } catch (IOException ioe) { 
      ioe.printStackTrace(); 
    } 
  } 
} 

Ant 实现批量打包Android应用
由于公司运维需要以及应用中需要加上应用推广的统计,往往要对应二三十个渠道,按照正常方法一个一个的去生成不同渠道包的应用,不仅浪费了时间,而且大大降低了效率.
上一篇讲到使用Ant进行Zip/Tar包的解压缩,实际上Ant工具不仅仅具有此类功能,它更强大的地方在于自动化调用程序完成项目的编译,打包,测试等. 类似于C语言中的make脚本完成这些工作的批处理任务. 不同于MakeFile的是,Ant是纯Java编写的,因此具有很好的跨平台性.

在此我主要讲下如何自动构建工具Ant,对应用进行批量打包,生成对应不同市场的应用:

首先分别看一下用于打包的Java工程AntTest和需要被打包进行发布的Android工程结构:

2016226144512430.jpg (519×200)

2016226144528909.jpg (537×356)

market.txt里保存需要打包的市场标识,如:

youmeng
gfan
.......

此文件里自行根据需求添加渠道名称.

然后看一下实现批量打包AntTest类中的内容:
注意:红色标注部分需要进行修改:

package com.cn.ant; 
 
import java.io.BufferedReader; 
import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileReader; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.Calendar; 
 
import org.apache.tools.ant.DefaultLogger; 
import org.apache.tools.ant.Project; 
import org.apache.tools.ant.ProjectHelper; 
 
public class AntTest { 
  private Project project; 
 
  public void init(String _buildFile,String _baseDir) throws Exception { 
    project = new Project(); 
 
    project.init(); 
 
    DefaultLogger consoleLogger = new DefaultLogger(); 
    consoleLogger.setErrorPrintStream(System.err); 
    consoleLogger.setOutputPrintStream(System.out); 
    consoleLogger.setMessageOutputLevel(Project.MSG_INFO); 
    project.addBuildListener(consoleLogger); 
 
    // Set the base directory. If none is given,"." is used. 
    if (_baseDir == null) 
      _baseDir = new String("."); 
 
    project.setBasedir(_baseDir); 
 
    if (_buildFile == null) 
      _buildFile = new String(projectBasePath + File.separator 
          + "build.xml"); 
 
    // ProjectHelper.getProjectHelper().parse(project,new 
    // File(_buildFile)); 
    <span style="color:#FF0000;">// 关键代码</span> 
    ProjectHelper.configureProject(project,new File(_buildFile)); 
  } 
 
  public void runTarget(String _target) throws Exception { 
    // Test if the project exists 
    if (project == null) 
      throw new Exception( 
          "No target can be launched because the project has not been initialized. Please call the 'init' method first !"); 
    // If no target is specified,run the default one. 
    if (_target == null) 
      _target = project.getDefaultTarget(); 
 
    // Run the target 
    project.executeTarget(_target); 
 
  } 
 
  <span style="color:#FF0000;">private final static String projectBasePath = "D:\\android\\workspace3\\XXX";//要打包的项目根目录 
  private final static String copyApkPath = "D:\\android\\apktest";//保存打包apk的根目录 
  private final static String signApk = "XXX-release.apk";//这里的文件名必须是准确的项目名! 
  private final static String reNameApk = "XXX_";//重命名的项目名称前缀(地图项目不用改) 
  private final static String placeHolder = "@market@";//需要修改manifest文件的地方(占位符) 
</span> 
  public static void main(String args[]) { 
    long startTime = 0L; 
    long endTime = 0L; 
    long totalTime = 0L; 
    Calendar date = Calendar.getInstance(); 
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss"); 
    try { 
      System.out.println("---------ant批量自动化打包开始----------"); 
      startTime = System.currentTimeMillis(); 
      date.setTimeInMillis(startTime); 
      System.out.println("开始时间为:" + sdf.format(date.getTime())); 
 
      BufferedReader br = new BufferedReader(new FileReader("market.txt")); 
      String flag = null; 
      while ((flag = br.readLine()) != null) { 
 
        // 先修改manifest文件:读取临时文件中的@market@修改为市场标识,然后写入manifest.xml中 
        String tempFilePath = projectBasePath + File.separator 
            + "AndroidManifest.xml.temp"; 
        String filePath = projectBasePath + File.separator 
            + "AndroidManifest.xml"; 
        write(filePath,read(tempFilePath,flag.trim())); 
        // 执行打包命令 
        AntTest mytest = new AntTest(); 
        mytest.init(projectBasePath + File.separator + "build.xml",projectBasePath); 
        mytest.runTarget("clean"); 
        mytest.runTarget("release"); 
        // 打完包后执行重命名加拷贝操作 
        File file = new File(projectBasePath + File.separator + "bin" 
            + File.separator + signApk);// bin目录下签名的apk文件 
         
        File renameFile = new File(copyApkPath + File.separator + reNameApk 
            + flag + ".apk"); 
        boolean renametag = file.renameTo(renameFile); 
        System.out.println("rename------>"+renametag); 
        System.out.println("file ------>"+file.getAbsolutePath()); 
        System.out.println("rename------>"+renameFile.getAbsolutePath()); 
      } 
      System.out.println("---------ant批量自动化打包结束----------"); 
      endTime = System.currentTimeMillis(); 
      date.setTimeInMillis(endTime); 
      System.out.println("结束时间为:" + sdf.format(date.getTime())); 
      totalTime = endTime - startTime; 
      System.out.println("耗费时间为:" + getBeapartDate(totalTime)); 
 
    } catch (Exception e) { 
      e.printStackTrace(); 
      System.out.println("---------ant批量自动化打包中发生异常----------"); 
      endTime = System.currentTimeMillis(); 
      date.setTimeInMillis(endTime); 
      System.out.println("发生异常时间为:" + sdf.format(date.getTime())); 
      totalTime = endTime - startTime; 
      System.out.println("耗费时间为:" + getBeapartDate(totalTime)); 
    } 
  } 
 
  /** 
   * 根据所秒数,计算相差的时间并以**时**分**秒返回 
   * 
   * @param d1 
   * @param d2 
   * @return 
   */ 
  public static String getBeapartDate(long m) { 
    m = m / 1000; 
    String beapartdate = ""; 
    int nDay = (int) m / (24 * 60 * 60); 
    int nHour = (int) (m - nDay * 24 * 60 * 60) / (60 * 60); 
    int nMinute = (int) (m - nDay * 24 * 60 * 60 - nHour * 60 * 60) / 60; 
    int nSecond = (int) m - nDay * 24 * 60 * 60 - nHour * 60 * 60 - nMinute 
        * 60; 
    beapartdate = nDay + "天" + nHour + "小时" + nMinute + "分" + nSecond + "秒"; 
 
    return beapartdate; 
  } 
 
  public static String read(String filePath,String replaceStr) { 
    BufferedReader br = null; 
    String line = null; 
    StringBuffer buf = new StringBuffer(); 
 
    try { 
      // 根据文件路径创建缓冲输入流 
      br = new BufferedReader(new FileReader(filePath)); 
 
      // 循环读取文件的每一行,对需要修改的行进行修改,放入缓冲对象中 
      while ((line = br.readLine()) != null) { 
        // 此处根据实际需要修改某些行的内容 
        if (line.contains(placeHolder)) { 
          line = line.replace(placeHolder,replaceStr); 
          buf.append(line); 
        } else { 
          buf.append(line); 
        } 
        buf.append(System.getProperty("line.separator")); 
      } 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } finally { 
      // 关闭流 
      if (br != null) { 
        try { 
          br.close(); 
        } catch (IOException e) { 
          br = null; 
        } 
      } 
    } 
 
    return buf.toString(); 
  } 
 
  /** 
   * 将内容回写到文件中 
   * 
   * @param filePath 
   * @param content 
   */ 
  public static void write(String filePath,String content) { 
    BufferedWriter bw = null; 
 
    try { 
      // 根据文件路径创建缓冲输出流 
      bw = new BufferedWriter(new FileWriter(filePath)); 
      // 将内容写入文件中 
      bw.write(content); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } finally { 
      // 关闭流 
      if (bw != null) { 
        try { 
          bw.close(); 
        } catch (IOException e) { 
          bw = null; 
        } 
      } 
    } 
  } 
} 


然后是Android工程中需要进行修改的部分:

1. 修改local.properties中的sdk根目录:

  sdk.dir=D:\\android\\android-sdk-windows-r17\\android-sdk-windows-r17

2. 修改ant.properties中签名文件的路径和密码(如果需要)

  key.store=D:\\android\\mykeystore
  key.store.password=123456
  key.alias=mykey
  key.alias.password=123456

3. 修改AndroidManifest.xml.temp
    拷贝AndroidManifest.xml一份,命名为AndroidManifest.xml.temp
    将需要替换的地方改为占位符,需与打包工程AntTest中的placeHolder常量一致
  如: <meta-data android:value="@market@" android:name="UMENG_CHANNEL"/>
4. Build.xml中:
    <project name="XXX" default="help">,XXX必须为Android工程名称.

如果机器没有配置过Ant环境变量,可根据如下步骤进行配置:

ANT环境变量设置:

Windows下ANT用到的环境变量主要有2个,ANT_HOME 、PATH。

设置ANT_HOME指向ant的安装目录。

设置方法:

ANT_HOME = D:/apache_ant_1.7.0

将%ANT_HOME%/bin; %ANT_HOME%/lib添加到环境变量的path中。

设置方法:

PATH = %ANT_HOME%/bin; %ANT_HOME%/lib 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 连接 连接池产生原因 连接池实现原理 小结 TEMPERANCE:Eat not to dullness;drink not to elevation.节制
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 一个优秀的工程师和一个普通的工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。-- 毕玄 1. 命名风格 【书摘】类名用 UpperCamelC
今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个人在用”。哪怕只是throw了一个新的Exception。哈哈,这是我犯的错误。一、接口和抽象类类,即一个对象。先抽象类,就是抽象出类的基础部分,即抽象基类(抽象类)。官方定义让人费解,但是记忆方法是也不错的 —包含抽象方法的类叫做抽象类。接口
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket一、引子文件,作为常见的数据源。关于操作文件的字节流就是 —FileInputStream&amp;FileOutputStream。
作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。交流QQ群:【编程之美 365234583】http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_Aonqz
本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程与多线程 线程是什么? 线程(Thread)是一个对象(Object)。用来干什么?Java 线程(也称 JVM 线程)是 Java 进程内允许多个同时进行的任务。该进程内并发的任务成为线程(Thread),一个进程里至少一个线程。 Ja
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket在面向对象编程中,编程人员应该在意“资源”。比如?1String hello = &quot;hello&quot;; 在代码中,我们
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 《程序兵法:Java String 源码的排序算法(一)》 文章工程:* JDK 1.8* 工程名:algorithm-core-le
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 一、父子类变量名相同会咋样? 有个小故事,今天群里面有个人问下面如图输出什么? 我回答:60。但这是错的,答案结果是 40 。我知错能改,然后说了下父子类变
作者:泥瓦匠 出处:https://www.bysocket.com/2021-10-26/mac-create-files-from-the-root-directory.html Mac 操作系统挺适合开发者进行写代码,最近碰到了一个问题,问题是如何在 macOS 根目录创建文件夹。不同的 ma
作者:李强强上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算。这一讲,泥瓦匠带你走进Java中的进制详解。一、引子在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?自问自答:在跨平台的时候,就凸显神功了。比如说文件读写,数据通信,还
1 线程中断 1.1 什么是线程中断? 线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 方法,使得该线程中断标志位属性改变。 深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一。原本以为来个时间戳,精确到毫秒应该不错了。后来觉得是错了,测试环境下很多一
纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 加微信:bysocket01
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want.文章Points:1、介绍RESTful架构风格2、Spring配置CXF3、三层初设计,实现WebService接口层4、撰写HTTPClient 客户
Writer :BYSocket(泥沙砖瓦浆木匠)什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道“就一个回调…”。此时千万个草泥马飞奔而过(逃哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉。不妨总结总结。一、什么是回调回调,回调。要先有调用,才有调用者和被调用者之间的回调。所以在百
Writer :BYSocket(泥沙砖瓦浆木匠)一、什么大小端?大小端在计算机业界,Endian表示数据在存储器中的存放顺序。百度百科如下叙述之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加
What is a programming language? Before introducing compilation and decompilation, let&#39;s briefly introduce the Programming Language. Programming la
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket泥瓦匠喜欢Java,文章总是扯扯Java。 I/O 基础,就是二进制,也就是Bit。一、Bit与二进制什么是Bit(位)呢?位是CPU
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocket一、前言 泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标:专注很重要。专注Java 基础 + H5(学习) 其他操作系统,算法,数据结构当成课外书博览。有时候,就是那样你越是专注方面越