stream和buffer的概念解析

1.概念解析

buffer:内存中一块确定的临时存储区域。
stream:一段不确定长度的数据序列,可以认为stream就是I/O中input部分的FIFO实现,为了方便理解,可以用键盘输入作为输入来举例,从键盘中敲入的字符组成一段stream,先敲入的字符先被读取,也就是FIFO,但是读取的过程中,你并不知道总共要读取多少,也就是长度的不确定性。

2.具体使用时的区别与联系

在使用 stream 的过程中,我们遵循这样一个基本的过程,以从文件中读取为例:
1.程序向 stream 发起请求,要读取一个字节。
2.stream 在磁盘上定为到请求的字节,并发送给程序。
3.程序得到这个字节后,在进行请求,重复到第一步

这个样子就有一个很严重的效率问题,读取一个字节需要在程序和stream之间来回一次,那么1000个字节就是1000次。怎么解决这个问题呢?

这时候就到 buffer 出场了,buffer 根据上面的概念,他是内存中一块确定的临时存储区域。如果使用一个 1000 字节的 buffer ,那么程序和 stream 的关系就变成:
1.程序向stream发起请求,要求stream将buffer填满。
2.stream向buffer中填充字节,要么填满1000个字节为止,要么stream到达结尾为止。
3.程序从buffer中一次性获取1000字节的数据

很明显,使用buffer的好处在于减少的请求IO的次数,也大大提升了效率

LINUX下修改php.ini配置报错输出

首先是找到php.ini文件

输入

find / -name php.ini

总共有两个结果

/etc/php5/cli/php.ini
/etc/php5/apache2/php.ini

cli/php.ini指的是在控制台环境下运行php脚本使用的配置文件

apache2/php.ini是apache2环境下运行php脚本使用的配置文件

如果你还不确定是用哪一个,可以新建一个php代码

使用 echo phpinfo(); 来输出php信息,其中有一项是加载的php.ini路径。我的就是apache2/php.ini

然后编辑apache2/php.ini,我这里是要开启他的报错,不然如果代码中有错,浏览器访问就会直接报500错误

找到display_errors这一行,去除前面的;

display_errors=On

配置错误级别

error_reporting=E_ALL & ~E_NOTICE

修改完成后要使php.ini配置生效,网上普遍的说法是重启apache服务生效

service apache2 restart

代码出错的地方仍然报500错误

准备去看apache的日志文件,同样使用find / -name error.log找到日志,由于日志太多,就把之前的error.log删掉,重启apache,浏览器打开出错页面,然后查看error.log。发现日志中是记录了代码出错的信息的。确定就是没有开启报错,导致500错误。

修改apache2.conf,在/etc/apache2下面。

添加

php_flag display_errors on
php_value error_reporting 2039

重启apache
service apache2 restart

浏览器打开错误页面,成功报错!

linux下一些好用的指令记录

查找当前目录下包含指定字符串的文件

grep -rn “hello,world!” *

  • : 表示当前目录所有文件,也可以是某个文件名
    -r 是递归查找
    -n 是显示行号
    -R 查找所有文件包含子目录
    -i 忽略大小写

mysql数据库相关操作
创建用户
mysql> insert into mysql.user(Host,User,Password) values(“localhost”,”phplamp”,password(“1234”));
授权

grant all privileges on phplampDB.* to phplamp@localhost identified by ‘1234’;
删除用户
mysql>DELETE FROM user WHERE User=”phplamp” and Host=”localhost”;
mysql>flush privileges;
修改密码
mysql>update mysql.user set password=password(‘新密码’) where User=”phplamp” and Host=”localhost”;
mysql>flush privileges;
刷新系统权限表
mysql>flush privileges;

cinnamon桌面图标重复
gsettings set org.gnome.desktop.background show-desktop-icons false

java反射机制以及在android开发中的应用

java中的反射机制:只要给定类的名字就可以得到所有类的信息。因为这个类的名字是可以在代码运行时动态指定的,所以利用java的反射机制比通过new的方式要灵活的多

在java中,通过new的方式创建的对象称为静态加载(编译时加载类),通过反射机制创建对象称为动态加载(运行时加载类)

java反射机制的使用方式

这里有个Human类如下

package com.myway5;

public class Human {
private String name;
private int age;
public String word;

public Human() {
    // TODO Auto-generated constructor stub
}

public Human(String name) {
    this.name = name;
}

public Human(String name, int age) {
    this.name = name;
    this.age = age;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}
public void speak(String word) {
     System.out.println(word);
 }

}
我们使用反射机制获取Human类所有的信息

package com.myway5;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Client {
public static void main(String[] args) {
// 获取类名等信息
Class class1 = Human.class;
System.out.println(class1.getName());
System.out.println(class1.getSimpleName());

    System.out.println("***********构造方法**********");

    Constructor[] cs = class1.getDeclaredConstructors();
    for (Constructor constructor : cs) {
        System.out.print(constructor.getName() + "(");
        Class[] paramsType = constructor.getParameterTypes();
        for (Class class2 : paramsType) {
            System.out.print(class2.getName() + ",");
        }
        System.out.println(")");
    }

    System.out.println("**********公共成员变量************");
    Field[] fields = class1.getFields();
    for (Field field : fields) {
        System.out.println(field.getType().getName() + ":" + field.getName());
    }

    System.out.println("**********公共方法**************");
    Method[] methods = class1.getMethods();
    for (Method method : methods) {
        System.out.print(method.getName() + "(");
        Class[] params = method.getParameterTypes();
        for (Class class3 : params) {
            System.out.print(class3.getName() + ",");
        }
        System.out.println(method.getReturnType().getName() + ")");
    }

}

}
输出结果如下:
com.myway5.Human
Human
***********构造方法**********
com.myway5.Human(java.lang.String,int,)
com.myway5.Human(java.lang.String,)
com.myway5.Human()
**********公共成员变量************
java.lang.String:word
**********公共方法**************
getName(java.lang.String)
setName(java.lang.String,void)
getAge(int)
setAge(int,void)
wait(long,int,void)
wait(long,void)
wait(void)
equals(java.lang.Object,boolean)
toString(java.lang.String)
hashCode(int)
getClass(java.lang.Class)
notify(void)
notifyAll(void)
可以看到,所有公共的成员变量,方法都可以通过这个方式获取到,那么怎么调用其中的方法呢
public static void useMethod() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException,
InstantiationException, NoSuchMethodException, SecurityException {
Class class1 = Human.class;
Human man = (Human) class1.newInstance();//通过newInstance创建实例
Method method = class1.getMethod(“speak”, String.class);
Object object = method.invoke(man, new Object[] { “hello reflect” });
}

android开发中的使用后续更新

继上文更新:

android开发中常常会使用java的反射机制来更改一些系统底层无法更改的代码逻辑。比如说在AlertDialog的使用中,通过自带的setPositiveButton或者setNegativeButton时,一旦点击按钮都会退出dialog,有时候我们不希望他退出,比如用户登录时登录失败再次登录。那么一种解决办法 就是通过java的反射机制。

package com.myway5.java_reflect;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;

public class MainActivity extends AppCompatActivity{

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    AlertDialog.Builder builder=new AlertDialog.Builder(this);

    builder.setMessage("Hello Dialog")
             .setTitle("对话框")
                .setView(getLayoutInflater().inflate(R.layout.dialog_signin,null));
    builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {

        }
    });
    builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {

        }
    });
    AlertDialog dialog=builder.create();
    try {
        Field field = dialog.getClass().getDeclaredField("mAlert");
        field.setAccessible(true);
        Object obj=field.get(dialog);
        field=obj.getClass().getDeclaredField("mHandler");
        field.setAccessible(true);
        field.set(obj,new ButtonHandler(dialog));
    }catch (Exception e){
        e.printStackTrace();
    }
    dialog.show();
}
private static final class ButtonHandler extends Handler {
    // Button clicks have Message.what as the BUTTON{1,2,3} constant
    private static final int MSG_DISMISS_DIALOG = 1;

    private WeakReference<DialogInterface> mDialog;

    public ButtonHandler(DialogInterface dialog) {
        mDialog = new WeakReference<DialogInterface>(dialog);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {

            case DialogInterface.BUTTON_POSITIVE:
            case DialogInterface.BUTTON_NEGATIVE:
            case DialogInterface.BUTTON_NEUTRAL:
                ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
                break;

            case MSG_DISMISS_DIALOG:
                //这里是点击后的逻辑,因为注释掉了dismiss(),dialog不会退出了
                //((DialogInterface) msg.obj).dismiss();
        }
    }
}

}
其中
try {
Field field = dialog.getClass().getDeclaredField(“mAlert”);
field.setAccessible(true);
Object obj=field.get(dialog);
field=obj.getClass().getDeclaredField(“mHandler”);
field.setAccessible(true);
field.set(obj,new ButtonHandler(dialog));
}catch (Exception e){
e.printStackTrace();
}
这个部分就是通过反射获取AlertDialog的私有变量mAlert,然后获取mAlert的成员变量mHandler,将这个Handler设置成我们自己的ButtonHandler,这样就解决了点击后退出的问题

代码地址:https://github.com/joyme123/java_reflect

参考文章:http://www.oschina.net/question/163910_27112

android studio导入项目出现Gradle version 1.10 is required. Current version is 2.0的解决办法

1.首先在项目下找到gradlew.bat这个文件,单击运行。它会下载Gradle 1.10 。等待任务完成

2.在项目的报错的控制台中选择setting这个选项。然后设置本地的Gradle。我的是默认放在

C:\Users\joyme.gradle\wrapper\dists\gradle-1.10-all\bif7dlrky2i400uf9zsz2c0my\gradle-1.10

vitamio使用出现找不到文件的解决方法

首先我遇到这个问题肯定不是一般的找不到文件的错误。使用vitamio的VideoView的时候,出现一部分视频会找不到文件。

分析很久问题出现的原因,最后得出是因为这部分视频名都是URLEncode过的,可能是这个原因导致字符串在解析的过程中出现问题。然后跟踪代码到VideoView的setVideoPath处,发现他的实现如下

public void setVideoPath(String path) {
setVideoURI(Uri.parse(path));
}
很明显这里就是导致错误所在,所以解决办法就是将string 类型的path先编码一下

videoView.setVideoPath(URLEncoder.encode(path, “UTF-8”));

java常量池

package 测试常量;

public class Test {
public static void main(String[] args){
String s1 = “hello world”;
String s2 = “hello world”;
System.out.println(s1==s2);

String s4 = new String(“你好”);
String s3 = “你好”;
System.out.println(s3==s4);

Integer i1 = 10;
Integer i2 = 10;
System.out.println(i1 == i2);

Integer i3 = 2000;
Integer i4 = 2000;
System.out.println(i3 == i4);

Integer i5 = new Integer(10);
Integer i6 = new Integer(10);
System.out.println(i5 == i6);

int i7 = 2000;
int i8 = 2000;
System.out.println(i7 == i8);

Double f1 = new Double(1.01);
Double f2 = new Double(1.01);
System.out.println(f1 == f2);

Double f3 = 1000.01;
Double f4 = 1000.01;
System.out.println(f3 == f4);

double f5 = 1000.01;
double f6 = 1000.01;
System.out.println(f5 == f6);
}
}


输出结果是

true
false
true
false
false
true
false
false
true

ubuntu下linux创建桌面启动器以及菜单栏点击失效的解决方法

创建桌面启动器

进入/usr/share/applications

vi eclipse.desktop

输入一下内容

[Desktop Entry]
Encoding=UTF-8
Name=eclipse
Comment=Eclipse IDE
Exec=/home/jiang/eclipse/eclipse
Icon=/home/jiang/eclipse/icon.xpm
Terminal=false
StartupNotify=true
Type=Application
Categories=Application;Development;
Exec=env UBUNTU_MENUPROXY=0 /home/jiang/eclipse/eclipse

保存后,将这个文件复制到桌面文件夹
cp /usr/share/applications/eclipse.desktop /home/jiang/桌面

对于eclipse打不开菜单的情况,可以修改eclipase文件夹下的eclipse.ini为

-startup
plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar
–launcher.GTK_version
2
–launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.300.v20150602-1417
-product
org.eclipse.epp.package.jee.product
–launcher.defaultAction
openFile
-showsplash
org.eclipse.platform
–launcher.XXMaxPermSize
256m
–launcher.defaultAction
openFile
–launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.7
-XX:MaxPermSize=256m
-Xms256m
-Xmx2048m

————————————

–launcher.GTK_version
2

这一部分是新增的部分

linux下编译安装mysql-connector-cpp

首先在github上下载mysql-connector-cpp

git clone https://github.com/mysql/mysql-connector-cpp.git

git上面有两个分支,2.0版本是支持mysql作为文档存储的接口,1.1版本是支持正常的关系数据库存储接口

首先我们编译安装2.0版本,进入代码目录执行

cmake .

cmake –build . –config CCC

cmake –build . –target install –config CCC

到这里已经安装完毕.

然后到testapp下编译测试样例

cmake .

提示出错,WITH-CONCPP没有设置,我试了编辑/etc/profile文件,设置这个变量为/usr/local/mysql/connector-c++-2.0/,但是仍然提示没有设置,于是我将CMakeLists中的

set(WITH_CONCPP $ENV{WITH_CONCPP} CACHE PATH “MySQL Connector/C++ 2.0 install location”)

改为

set(WITH_CONCPP “/usr/local/mysql/connector-c++-2.0/” CACHE PATH “MySQL Connector/C++ 2.0 install location”)

继续cmake .

提示出错,在/usr/local/mysql/connector-c++-2.0/lib64下找不到依赖库

那么将目录下生成的 libmysqlcppconn2.so libmysqlcppconn2.so.1 libmysqlcppconn2.so.1.0 拷贝到/usr/local/mysql/connector-c++-2.0/lib64中,没有的创建一个即可。

cmake .

make

在run文件夹下面生成了两个可执行文件

devapi_test xapi_test

这两个文件的区别在于,xapi_test实现了c的接口,是通过mysql的一个叫做x plugin的插件连接mysql的,而devapi则是使用了c++的接口。所以如果使用xapi接口的话,mysql安装时必须安装x plugin

接下来编译安装1.1版本,先将当前的改动都commit了,然后

git checkout 1.1,

cmake .

如果出错。

报缺少boost库错误,可以

sudo apt-get install libboost-all-dev

报缺少mysql.h等错误,可以通过sudo apt-get install libmysql++-dev

然后make

sudo make install

然后将生成的动态库拷贝的/usr/local/lib下

sudo cp libmysqlcppconn.so* /usr/local/lib/

c++中的中文字符分割

在utf-8编码的前提下,一个字符可能占用的空间为1~4个char,由于这种不确定的字符长度导致在utf-8编码的string中,无法直接使用substr进行字符串分割。

解决的方案的关键在于利用utf-8编码的特点,utf-8的第一个字符的前缀连续为1的个数代表这个”字“占用的字符数量,当只有一个字符时,第一个字符的第一位为0。具体的说明可以参考这篇文章。http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

这里主要说明怎么利用代码解决这个问题

int getUtf8CharLength(char c){
    int len = 0;
    if(c > 0){              //利用计算机中数字的存储特点,第一位为1为负,第一位为0为正,很容易判断
        return len + 1;     //第一位为0时为特殊情况,需要加1
    }
    while(c < 0){
        len++;
        c = c << 1;
    }
    return len;
}

std::string substrWithChinese(std::string str,unsigned int start,unsigned int length){
    unsigned int i = 0;             //标识前进的几个“字符”
    unsigned int cursor = 0;        //标识前进了几个“字”
    unsigned int save = 0;          //保存的字符标识
    unsigned int len = str.length();
    char* c = new char[len + 1];
    while(str[i] != '\0'&&length > 0){
        unsigned int l = getUtf8CharLength(str[i]); //获取字符长度
        if(cursor >= start){
            unsigned int m = l;
            while(m--){
                c[save++] = str[i++];
            }
            length--;
        }else{
            i+=l;
        }
        cursor++;
    }
    c[i] = '\0';
    return std::string(c);
}